/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-  */
/*
 * LiberAcus
 * Copyright (C) 2012 - 2014 Massimiliano Maniscalco <max.maniscalco@gmail.com>
 * 
LiberAcus is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * LiberAcus is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "controller.h"
#include "parser_xml.h"
#include "ricevuta_print_form_operation.h"
#include "etichetta_print_form_operation.h"
#include "chiusura_cassa_print_form_operation.h"

bool Controller::
save_data ( const Glib::ustring &filename, char what )
{
	struct tm *data_ora;
	time_t tempo = time(NULL);
	data_ora = localtime (&tempo);
	Glib::ustring messaggio ( "Ho salvato " );
	int n = 0;
	bool result = true;
	ofstream outfile ( filename.c_str(), ios_base::out );
	if ( !outfile )
		cerr << "ERRORE! save_data():: unable to open file \"" << filename << "\"" << endl;
	else
	{
		outfile << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
		outfile << "<LiberAcus>\n";
		switch ( what )
		{
			case SAVE_CLIENTI:
				n = save_items_to_xml_file ( *clienti, &outfile );
				if ( n != clienti->size() )
					result = false;
				else
				{
					if ( n == 1 )
						messaggio.append ( "un cliente" );
					else
						messaggio.append ( Glib::ustring::compose("%1 clienti", Glib::ustring::format(n) ) );
				}
				messaggio.append ( ", " );
				break;
			case SAVE_PRESTAZIONI:
				n = save_items_to_xml_file ( *prestazioni, &outfile );
				if ( n != prestazioni->size() )
					result = false;
				else
				{
					if ( n == 1 )
						messaggio.append ( "una prestazione" );
					else
						messaggio.append ( Glib::ustring::compose("%1 prestazioni", Glib::ustring::format(n) ) );
				}
				messaggio.append ( ", " );
				break;
			case SAVE_RICEVUTE:
				outfile << Glib::ustring ( "\t<data_salvataggio>" + Glib::ustring::compose ( "%1-%2-%3", Glib::ustring::format ( setfill(L'0'), setw(4), data_ora->tm_year + 1900 ), Glib::ustring::format ( setfill(L'0'), setw(2), data_ora->tm_mon + 1 ), Glib::ustring::format ( setfill(L'0'), setw(2), data_ora->tm_mday ) ) + "</data_salvataggio>\n" );
				outfile << Glib::ustring ( "\t<ultimo_numero>" + Glib::ustring::format ( Ricevuta::get_last_numero_ricevuta() ) + "</ultimo_numero>\n" );
				n = save_items_to_xml_file ( *ricevute, &outfile );
				if ( n != ricevute->size() )
					result = false;
				else
				{
					if ( n == 1 )
						messaggio.append ( "una ricevuta" );
					else
						messaggio.append ( Glib::ustring::compose("%1 ricevute", Glib::ustring::format(n) ) );
				}
				break;
		}
		outfile << "</LiberAcus>";
		if ( outfile.fail() )
			result = false;
		outfile.close();
	}
	main_statusbar->pop ( stbrItemDiskId );
	if ( result )
	{
		main_statusbar->push ( messaggio, stbrItemDiskId );
		switch ( what )
		{
			case SAVE_CLIENTI:
				clienti_changed = false;
				break;
			case SAVE_PRESTAZIONI:
				prestazioni_changed = false;
				break;
			case SAVE_RICEVUTE:
				ricevute_changed = false;
				break;
		}
	}
	else
		main_statusbar->push ( Glib::ustring ( "Errore di salvataggio dei dati!" ), stbrItemDiskId );
	return result;
}

template <class ItemClass>
int Controller::
save_items_to_xml_file ( list<ItemClass> &items_list, ofstream *xmlstr )
{
	int ni = -1;
	if ( !*xmlstr )
		cerr << "ERRORE! save_items_to_xml_file():: unable to open file!" << endl;
	else
	{
		ni++;
		class list<ItemClass>::iterator tc_iter = items_list.begin();
		class list<ItemClass>::iterator tc_end = items_list.end();
		while ( tc_iter != tc_end )
		{
			*xmlstr << tc_iter->get_xml_string ().raw();
			if ( xmlstr->fail() )
			{
				cerr << "ERRORE! save_items_to_xml_file():: file writing error!"<< endl;
				break;
			}
			tc_iter++;
			ni++;
		}
	}
	return ni;
}

template <class ItemClass>
int Controller::
save_items_to_xml_file ( set<ItemClass> &items_set, ofstream *xmlstr )
{
	int ni = -1;
	if ( !*xmlstr )
		cerr << "ERRORE! save_items_to_xml_file():: unable to open file!" << endl;
	else
	{
		ni++;
		class set<ItemClass>::iterator const_iter = items_set.begin();
		class set<ItemClass>::iterator const_end = items_set.end();
		while ( const_iter != const_end )
		{
			*xmlstr << const_iter->get_xml_string ().raw();
			if ( xmlstr->fail() )
			{
				cerr << "ERRORE! save_items_to_xml_file():: file writing error!"<< endl;
				break;
			}
			const_iter++;
			ni++;
		}
	}
	return ni;
}

void Controller::
load_data ( void )
{
	Glib::RefPtr<Gio::File> file_clienti = Gio::File::create_for_path ( clienti_file_path );
	if ( file_clienti->query_exists () )
	{
		starting_app = STATUS_LOADING;
		bool result;
		main_statusbar->push ( "Caricamento clienti...", stbrItemDiskId );
		result = load_clienti_from_xml_file ( clienti_file_path );
		if ( !result )
			main_statusbar->push ( Glib::ustring ( "Errore di caricamento dei clienti!" ), stbrItemDiskId );
	}
	Glib::RefPtr<Gio::File> file_prestazioni = Gio::File::create_for_path ( prestazioni_file_path );
	if ( file_prestazioni->query_exists () )
	{
		starting_app = STATUS_LOADING;
		bool result;
		main_statusbar->push ( "Caricamento prestazioni...", stbrItemDiskId );
		result = load_prestazioni_from_xml_file ( prestazioni_file_path );
		if ( !result )
			main_statusbar->push ( Glib::ustring ( "Errore di caricamento delle prestazioni!" ), stbrItemDiskId );
	}
	Glib::RefPtr<Gio::File> file_ricevute = Gio::File::create_for_path ( ricevute_file_path );
	if ( file_ricevute->query_exists () )
	{
		starting_app = STATUS_LOADING;
		bool result;
		main_statusbar->push ( "Caricamento ricevute...", stbrItemDiskId );
		result = load_ricevute_from_xml_file ( ricevute_file_path );
		if ( !result )
			main_statusbar->push ( Glib::ustring ( "Errore di caricamento delle ricevute!" ), stbrItemDiskId );
	}
}

bool Controller::
load_clienti_from_xml_file ( const Glib::ustring &filename )
{
	bool result = false;
	if ( filename != Glib::ustring ( "" ) )
	{
		sigc::connection parser_xml_cliente_imported;
		sigc::connection parser_xml_importing_end;
		// Parse the entire document in one go:
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		try
		{
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED 
			ParserXML parser;
			parser.set_substitute_entities(true); //
			clienti_caricati = 0;
			result = true;
			parser_xml_cliente_imported = parser.signal_cliente_imported ().connect (sigc::mem_fun (this, &Controller::on_signal_cliente_loaded) );
			parser_xml_importing_end = parser.signal_importing_end ().connect (sigc::mem_fun (this, &Controller::on_signal_importing_clienti_end) );
			parser.parse_file(filename);
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		}
		catch(const xmlpp::exception& ex)
		{
			std::cout << "libxml++ exception: " << ex.what() << std::endl;
			result = false;
		}
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
		parser_xml_cliente_imported.disconnect ();
		parser_xml_importing_end.disconnect ();
	}
	return result;
}

bool Controller::
load_prestazioni_from_xml_file ( const Glib::ustring &filename )
{
	bool result = false;
	if ( filename != Glib::ustring ( "" ) )
	{
		sigc::connection parser_xml_prestazione_imported;
		sigc::connection parser_xml_importing_end;
		// Parse the entire document in one go:
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		try
		{
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED 
			ParserXML parser;
			parser.set_substitute_entities(true); //
			prestazioni_caricate = 0;
			result = true;
			parser_xml_prestazione_imported = parser.signal_prestazione_imported ().connect (sigc::mem_fun (this, &Controller::on_signal_prestazione_loaded) );
			parser_xml_importing_end = parser.signal_importing_end ().connect (sigc::mem_fun (this, &Controller::on_signal_importing_prestazioni_end) );
			parser.parse_file(filename);
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		}
		catch(const xmlpp::exception& ex)
		{
			std::cout << "libxml++ exception: " << ex.what() << std::endl;
			result = false;
		}
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
		parser_xml_prestazione_imported.disconnect();
		parser_xml_importing_end.disconnect ();
	}
	return result;
}

bool Controller::
load_ricevute_from_xml_file ( const Glib::ustring &filename )
{
	bool result = false;
	if ( filename != Glib::ustring ( "" ) )
	{
		sigc::connection parser_xml_file_date;
		sigc::connection parser_xml_ricevuta_imported;
		sigc::connection parser_xml_importing_end;
		// Parse the entire document in one go:
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		try
		{
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED 
			ParserXML parser;
			parser.set_substitute_entities(true); //
			ricevute_caricate = 0;
			result = true;
			parser_xml_file_date = parser.signal_date_file ().connect (sigc::mem_fun (this, &Controller::on_signal_date_file) );
			parser_xml_ricevuta_imported = parser.signal_ricevuta_imported ().connect (sigc::mem_fun (this, &Controller::on_signal_ricevuta_loaded) );
			parser_xml_importing_end = parser.signal_importing_end ().connect (sigc::mem_fun (this, &Controller::on_signal_importing_ricevute_end) );
			parser.parse_file(filename);
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		}
		catch(const xmlpp::exception& ex)
		{
			std::cout << "libxml++ exception: " << ex.what() << std::endl;
			result = false;
		}
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
		parser_xml_file_date.disconnect ();
		parser_xml_ricevuta_imported.disconnect();
		parser_xml_importing_end.disconnect ();
	}
	return result;
}

void Controller::
load_preferences ( const Glib::ustring &filename )
{
	Glib::RefPtr<Gio::File> data_file = Gio::File::create_for_path ( filename );
	if ( data_file->query_exists () )
	{
		bool result;
		main_statusbar->push ( "Caricamento preferenze...", stbrItemDiskId );
		sigc::connection parser_xml_preferenze_loaded;		
		sigc::connection parser_xml_importing_end;
		// Parse the entire document in one go:
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		try
		{
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED 
			ParserXML parser;
			parser.set_substitute_entities(true); //
			result = true;
			parser_xml_preferenze_loaded = parser.signal_preferenze_loaded ().connect (sigc::mem_fun (this, &Controller::on_signal_preferenze_loaded));
			parser_xml_importing_end = parser.signal_importing_end ().connect (sigc::mem_fun (this, &Controller::on_signal_preferenze_loading_end) );
			parser.parse_file(filename);
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
		}
		catch(const xmlpp::exception& ex)
		{
			std::cout << "libxml++ exception: " << ex.what() << std::endl;
			result = false;
		}
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
		parser_xml_preferenze_loaded.disconnect ();
		parser_xml_importing_end.disconnect ();
		if ( !result )
			main_statusbar->push ( Glib::ustring ( "Errore di caricamento delle preferenze!" ), stbrItemDiskId );
	}
}

bool Controller::
save_preferences ( const Glib::ustring &filename )
{
	bool result;
	ofstream outfile ( filename.c_str(), ios_base::out );
	if ( !outfile )
	{
		cerr << "ERRORE! save_preferences():: unable to open file \"" << filename << "\"" << endl;
		result = false;
	}
	else
	{
		result = true;
		outfile << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
		outfile << "<LiberAcus_preferences>\n";
		outfile << preferenze.get_xml_string ().raw();		
		outfile << "</LiberAcus_preferences>";
		if ( outfile.fail() )
			result = false;
		outfile.close();
	}
	return result;
}

template <class ItemClass, typename Iterator>
void Controller::
replace_items ( set<ItemClass>* items_set, Iterator iter, const ItemClass& item )
{
	bool hint_is_valid = false;
	Iterator hint = iter;
	if (hint != items_set->begin())
	{
		hint--;
		hint_is_valid = true;
	}
	items_set->erase(iter);
	if (items_set->size() > 0 && hint_is_valid)
		items_set->insert(hint, item);
	else
		items_set->insert(item);
}

void Controller::
connect_signals ( void )
{
	// timers
	save_timer_connection = Glib::signal_timeout ().connect_seconds (sigc::mem_fun (*this, &Controller::on_auto_save_fired), 300 );
	// main menu
	nuova_ricevuta_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_new_ricevuta_action) );
	nuova_prestazione_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_new_prestazione_action) );
	nuovo_cliente_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_new_cliente_action) );
	salva_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_save_action) );
	imposta_pagina_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_page_setup_action) );
	stampa_ricevuta_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_print_ricevuta_action) );
	stampa_etichette_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_print_etichette_action) );
	stampa_chiusura_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_stampa_chiusura_cassa_action) );
	quit_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_quit_app_action) );
	modifica_selezione_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_edit_item_action) );
	elimina_selezione_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_remove_item_action) );
	preferenze_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_preferenze_action) );
	settimana_menuitem->signal_activate ().connect (sigc::bind<const unsigned short>(sigc::mem_fun (this, &Controller::on_visualizza_action), PAGINA_CALENDARIO ) );
	ricevute_menuitem->signal_activate ().connect (sigc::bind<const unsigned short>(sigc::mem_fun (this, &Controller::on_visualizza_action), PAGINA_RICEVUTE ) );
	prestazioni_menuitem->signal_activate ().connect (sigc::bind<const unsigned short>(sigc::mem_fun (this, &Controller::on_visualizza_action), PAGINA_PRESTAZIONI ) );
	clienti_menuitem->signal_activate ().connect (sigc::bind<const unsigned short>(sigc::mem_fun (this, &Controller::on_visualizza_action), PAGINA_CLIENTI ) );
	resoconto_menuitem->signal_activate ().connect (sigc::bind<const unsigned short>(sigc::mem_fun (this, &Controller::on_visualizza_action), PAGINA_RESOCONTO ) );
	about_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_about_app_action) );
	// main toolbar
	nuova_ricevuta_button->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_new_ricevuta_action) );
	nuova_prestazione_button->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_new_prestazione_action) );
	nuovo_cliente_button->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_new_cliente_action) );
	modifica_selezione_toolbutton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_edit_item_action) );
	elimina_selezione_toolbutton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_remove_item_action) );
	stampa_chiusura_toolbutton->signal_clicked ().connect (sigc::mem_fun (this, &Controller::on_stampa_chiusura_cassa_action) );
	// main window
	main_window->signal_focus_in_event ().connect (sigc::mem_fun (this, &Controller::on_main_window_focus_in) );
	main_window->signal_focus_out_event ().connect (sigc::mem_fun (this, &Controller::on_main_window_focus_out) );
	main_notebook->signal_switch_page ().connect (sigc::mem_fun (this, &Controller::on_main_notebook_page_switch) );

	/**
	 * main notebook
	 * */
	
	// page calendario
	ricevute_lunedi_treeselection->signal_changed ().connect ( sigc::bind<const short>( sigc::mem_fun (this, &Controller::on_ricevute_del_giorno_treeselection_changed), 0 ) );
	ricevute_martedi_treeselection->signal_changed ().connect ( sigc::bind<const short>( sigc::mem_fun (this, &Controller::on_ricevute_del_giorno_treeselection_changed), 1 ) );
	ricevute_mercoledi_treeselection->signal_changed ().connect ( sigc::bind<const short>( sigc::mem_fun (this, &Controller::on_ricevute_del_giorno_treeselection_changed), 2 ) );
	ricevute_giovedi_treeselection->signal_changed ().connect ( sigc::bind<const short>( sigc::mem_fun (this, &Controller::on_ricevute_del_giorno_treeselection_changed), 3 ) );
	ricevute_venerdi_treeselection->signal_changed ().connect ( sigc::bind<const short>( sigc::mem_fun (this, &Controller::on_ricevute_del_giorno_treeselection_changed), 4 ) );
	ricevute_sabato_treeselection->signal_changed ().connect ( sigc::bind<const short>( sigc::mem_fun (this, &Controller::on_ricevute_del_giorno_treeselection_changed), 5 ) );
	completoCellrenderertoggle->signal_toggled ().connect (sigc::mem_fun (this, &Controller::on_calendario_prestazione_completa_toggled) );
	
	// page ricevute
	ricevute_treeview->signal_button_press_event ().connect_notify (sigc::mem_fun (this, &Controller::on_treeview_clicked) );
	ricevute_treeselection->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_items_treeselection_changed) );
	urgente_cellrenderertoggle->signal_toggled ().connect (sigc::mem_fun (this, &Controller::on_ricevuta_urgente_toggled) );
	consegnato_cellrenderertoggle->signal_toggled ().connect (sigc::mem_fun (this, &Controller::on_ricevuta_consegnato_toggled) );
	// menu contestuale ricevute
	modifica_ricevute_context_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_edit_item_action) );
	elimina_ricevute_context_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_remove_item_action) );
	stampa_ricevute_context_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_print_ricevuta_action) );
	stampa_etichette_context_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_print_etichette_action) );
	
	// page prestazioni
	prestazioni_treeview->signal_button_press_event ().connect_notify (sigc::mem_fun (this, &Controller::on_treeview_clicked) );
	prestazioni_treeselection->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_items_treeselection_changed) );
	
	// page clienti
	clienti_treeview->signal_button_press_event ().connect_notify (sigc::mem_fun (this, &Controller::on_treeview_clicked) );
	clienti_treeselection->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_items_treeselection_changed) );
	// menu contestuale generico
	edit_generic_context_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_edit_item_action) );
	remove_generic_context_menuitem->signal_activate ().connect (sigc::mem_fun (this, &Controller::on_remove_item_action) );
	
	// page resoconto
	selezione_periodo_combobox->signal_changed ().connect ( sigc::mem_fun (this, &Controller::aggiorna_pagina_resoconto) );
	
	// new ricevuta window
	trova_clienti_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_trova_clienti_action) );
	cambia_data_ricevuta_button1->signal_clicked ().connect ( sigc::bind<Gtk::Button*>( sigc::mem_fun (this, &Controller::on_cambia_data_ricevuta_action), cambia_data_ricevuta_button1 ) );
	cambia_data_ricevuta_button2->signal_clicked ().connect ( sigc::bind<Gtk::Button*>( sigc::mem_fun (this, &Controller::on_cambia_data_ricevuta_action), cambia_data_ricevuta_button2 ) );
	prestazioni_ricevuta_connection = prestazioni_ricevuta_treeselection->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_prestazioni_ricevuta_selection_changed) );
	capo_popup_connection = selezione_capo_combobox->signal_changed ().connect (sigc::mem_fun (this, &Controller::load_prestazione_popup_button) );
	prestazione_popup_connection = selezione_prestazione_combobox->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_selezione_prestazione_popup_changed) );
	prestazioni_ricevuta_treeview->signal_row_expanded ().connect(sigc::mem_fun (this, &Controller::on_prestazioni_ricevuta_row_expanded));
	add_prestazione_ricevuta_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_add_prestazione_ricevuta_action) );
	rem_prestazione_ricevuta_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_remove_prestazione_ricevuta_action) );
	prezzo_prestazione_cellrenderertext->signal_edited ().connect ( sigc::mem_fun (this, &Controller::on_prezzo_modificato) );
	nonpagato_radiobutton->signal_toggled ().connect ( sigc::mem_fun (this, &Controller::on_pagamento_anticipato_toggled) );
	pagato_radiobutton->signal_toggled ().connect ( sigc::mem_fun (this, &Controller::on_pagamento_anticipato_toggled) );
	new_ricevuta_cancel_button->signal_clicked ().connect ( sigc::bind<Gtk::Window*>( sigc::mem_fun (this, &Controller::on_cancel_button_clicked), new_ricevuta_window ) );
	new_ricevuta_confirm_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_conferma_ricevuta_button_action) );
	// new prestazione window
	new_prestazione_confirm_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_new_prestazione_confirm_button_clicked) );
	new_prestazione_cancel_button->signal_clicked ().connect ( sigc::bind<Gtk::Window*>( sigc::mem_fun (this, &Controller::on_cancel_button_clicked), new_prestazione_window ) );
	// new cliente window
	new_cliente_confirm_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_new_cliente_confirm_button_clicked) );
	new_cliente_cancel_button->signal_clicked ().connect ( sigc::bind<Gtk::Window*>( sigc::mem_fun (this, &Controller::on_cancel_button_clicked), new_cliente_window ) );	
	// calendario window
	calendario_window->signal_hide ().connect ( sigc::mem_fun (this, &Controller::on_calendario_window_hide) );
	// preferenze window
	visualizza_numero_ricevuta_checkbutton->signal_toggled ().connect(sigc::mem_fun (this, &Controller::on_visualizza_numero_toggled));
	preferenze_annulla_button->signal_clicked ().connect ( sigc::bind<Gtk::Window*>( sigc::mem_fun (this, &Controller::on_cancel_button_clicked), preferenze_window ) );
	preferenze_salva_button->signal_clicked ().connect ( sigc::mem_fun (this, &Controller::on_salva_preferenze_action) );
	// suggerimento clienti window
	clienti_suggerimento_treeview->signal_button_press_event ().connect_notify (sigc::mem_fun (this, &Controller::on_suggerimento_clienti_double_clicked) );
}

void Controller::
on_cancel_button_clicked ( Gtk::Window *win )
{
	win->hide ();
}

bool Controller::
on_auto_save_fired ( void )
{
	on_save_action();
	return true;
}

set<Prestazione>::iterator Controller::
find_prestazione ( const Glib::ustring& capo, const Glib::ustring& descrizione )
{
	Prestazione temp = Prestazione ( capo, descrizione, 0.0 );
	return prestazioni->find(temp);
}

bool Controller::
on_main_window_focus_in ( GdkEventFocus *event )
{
	if ( starting_app == STATUS_STARTING )
	{
		Glib::ustring printer_conf;
		Glib::RefPtr<Gio::File> file_printer = Gio::File::create_for_path ( page_setup_path );
		if ( file_printer->query_exists () )
		{
			if ( printer_keyfile->load_from_file (page_setup_path, Glib::KEY_FILE_NONE) )
				m_refPageSetup->load_from_key_file (*printer_keyfile);
			else
				cerr << "ERRORE! on_main_window_focus_in():: failed to load page setup from key file!" << endl;
		}
		load_preferences ( pref_path );
		Glib::Threads::Thread *loader = Glib::Threads::Thread::create (sigc::mem_fun (this, &Controller::load_data));
		starting_app = STATUS_LOADING;
	}
	main_menubar->set_sensitive ( true );
	main_toolbar->set_sensitive ( true );
	ricevute_treeview->set_sensitive ( true );
	prestazioni_treeview->set_sensitive ( true );
	clienti_treeview->set_sensitive ( true );
	update_visualizza_numero(preferenze.get_visualizza_numero_ricevuta ());
	return false;
}

bool Controller::
on_main_window_focus_out ( GdkEventFocus *event )
{
	main_menubar->set_sensitive ( false );
	main_toolbar->set_sensitive ( false );
	switch ( main_notebook_page )
	{
		case PAGINA_RICEVUTE:
			ricevute_treeview->set_sensitive ( false );
			break;
		case PAGINA_PRESTAZIONI:
			prestazioni_treeview->set_sensitive ( false );
			break;
		case PAGINA_CLIENTI:
			clienti_treeview->set_sensitive ( false );
			break;
	}
	return false;
}

void Controller::
on_main_notebook_page_switch ( Gtk::Widget *page, guint page_num )
{
	main_notebook_page = page_num;
	on_items_treeselection_changed ();
}

void Controller::
on_items_treeselection_changed ( void )
{
	Glib::ustring messaggio;
	int nr = 0;
	switch ( main_notebook_page )
	{
		case PAGINA_CALENDARIO:
			settimana_menuitem->set_sensitive ( false );
			ricevute_menuitem->set_sensitive ( true );
			prestazioni_menuitem->set_sensitive ( true );
			clienti_menuitem->set_sensitive ( true );
			resoconto_menuitem->set_sensitive ( true );
			stampa_ricevuta_menuitem->set_sensitive ( false );
			stampa_etichette_menuitem->set_sensitive ( false );
			aggiorna_pagina_calendario ();
			break;
		case PAGINA_RICEVUTE:
			settimana_menuitem->set_sensitive ( true );
			ricevute_menuitem->set_sensitive ( false );
			prestazioni_menuitem->set_sensitive ( true );
			clienti_menuitem->set_sensitive ( true );
			resoconto_menuitem->set_sensitive ( true );
			nr = ricevute_treeselection->count_selected_rows ();
			if ( nr == 0 )
				messaggio.append ( Glib::ustring::compose( "Nessuna ricevuta selezionata di %1.", Glib::ustring::format( ricevute->size() ) ) );
			if ( nr == 1 )
				messaggio.append ( Glib::ustring::compose( "Una ricevuta selezionata di %1.", Glib::ustring::format( ricevute->size() ) ) );
			if ( nr > 1 )
				messaggio.append ( Glib::ustring::compose( "%1 ricevute selezionate di %2.", Glib::ustring::format( nr ), Glib::ustring::format( ricevute->size() ) ) );
			if ( nr > 0 )
			{
				stampa_ricevuta_menuitem->set_sensitive ( true );
				stampa_etichette_menuitem->set_sensitive ( true );
			}
			else
			{
				stampa_ricevuta_menuitem->set_sensitive ( false );
				stampa_etichette_menuitem->set_sensitive ( false );
			}
			break;
		case PAGINA_PRESTAZIONI:
			settimana_menuitem->set_sensitive ( true );
			ricevute_menuitem->set_sensitive ( true );
			prestazioni_menuitem->set_sensitive ( false );
			clienti_menuitem->set_sensitive ( true );
			resoconto_menuitem->set_sensitive ( true );
			stampa_ricevuta_menuitem->set_sensitive ( false );
			stampa_etichette_menuitem->set_sensitive ( false );
			nr = prestazioni_treeselection->count_selected_rows ();
			if ( nr == 0 )
				messaggio.append ( Glib::ustring::compose( "Nessuna prestazione selezionato di %1.", Glib::ustring::format( prestazioni->size() ) ) );
			if ( nr == 1 )
				messaggio.append ( Glib::ustring::compose( "Una prestazione selezionato di %1.", Glib::ustring::format( prestazioni->size() ) ) );
			if ( nr > 1 )
				messaggio.append ( Glib::ustring::compose( "%1 prestazioni selezionati di %2.", Glib::ustring::format( nr ), Glib::ustring::format( prestazioni->size() ) ) );
			break;
		case PAGINA_CLIENTI:
			settimana_menuitem->set_sensitive ( true );
			ricevute_menuitem->set_sensitive ( true );
			prestazioni_menuitem->set_sensitive ( true );
			clienti_menuitem->set_sensitive ( false );
			resoconto_menuitem->set_sensitive ( true );
			stampa_ricevuta_menuitem->set_sensitive ( false );
			stampa_etichette_menuitem->set_sensitive ( false );
			nr = clienti_treeselection->count_selected_rows ();
			if ( nr == 0 )
				messaggio.append ( Glib::ustring::compose( "Nessun cliente selezionato di %1.", Glib::ustring::format( clienti->size() ) ) );
			if ( nr == 1 )
				messaggio.append ( Glib::ustring::compose( "Un cliente selezionato di %1.", Glib::ustring::format( clienti->size() ) ) );
			if ( nr > 1 )
				messaggio.append ( Glib::ustring::compose( "%1 clienti selezionati di %2.", Glib::ustring::format( nr ), Glib::ustring::format( clienti->size() ) ) );
			break;
		case PAGINA_RESOCONTO:
			settimana_menuitem->set_sensitive ( true );
			ricevute_menuitem->set_sensitive ( true );
			prestazioni_menuitem->set_sensitive ( true );
			clienti_menuitem->set_sensitive ( true );
			resoconto_menuitem->set_sensitive ( false );
			stampa_ricevuta_menuitem->set_sensitive ( false );
			stampa_etichette_menuitem->set_sensitive ( false );
			aggiorna_pagina_resoconto ();
			break;
	}
	main_statusbar->pop ( stbrItemSelId );
	main_statusbar->push ( messaggio, stbrItemSelId );
	if ( nr > 0 )
	{
		elimina_selezione_toolbutton->set_sensitive ( true );
		elimina_selezione_menuitem->set_sensitive ( true );
		modifica_selezione_toolbutton->set_sensitive ( true );
		modifica_selezione_menuitem->set_sensitive ( true );
	}
	else
	{
		elimina_selezione_toolbutton->set_sensitive ( false );
		elimina_selezione_menuitem->set_sensitive ( false );
		modifica_selezione_toolbutton->set_sensitive ( false );
		modifica_selezione_menuitem->set_sensitive ( false );
	}
}

void Controller::
get_treeview_row_reference ( const vector<Gtk::TreePath> &_sel, Glib::RefPtr<Gtk::TreeModel> _listModel, vector<Gtk::TreeRowReference> &_selRef )
{
	vector<Gtk::TreePath>::const_iterator _iter = _sel.begin();
	vector<Gtk::TreePath>::const_iterator _end = _sel.end();
	while ( _iter != _end )
	{
		Gtk::TreeRowReference _ref = Gtk::TreeRowReference ( _listModel, *_iter );
		_selRef.push_back ( _ref );
		_iter++;
	}
}

void Controller::
load_popup_button ( vector<Glib::ustring>::iterator start, vector<Glib::ustring>::iterator end, Glib::RefPtr<Gtk::ListStore> popUpList )
{
	while ( start != end )
	{
		Gtk::TreeModel::iterator iter = popUpList->append();
		Gtk::TreeModel::Row row = *iter;
		row[button_popup_listmodel->column] = *start;
		start++;
	}
}

void Controller::
on_new_ricevuta_action ( void )
{
	struct tm *data_ora;
	time_t tempo = time(NULL);
	main_notebook->set_current_page (PAGINA_RICEVUTE);
	ricevute_treeselection->unselect_all ();
	new_ricevuta_window->set_title ( "Nuova Ricevuta" );
	cliente_ricevuta_entry->set_text ( "" );
	urgente_ricevuta_checkbutton->set_active (false);
	data_accettazione_ricevuta_entry->set_text ( Ricevuta::get_string_data ( tempo, HUMAN_FORMAT ) );
	tempo = calcola_data_ritiro ( tempo );
	data_ritiro_ricevuta_entry->set_text ( Ricevuta::get_string_data ( tempo, HUMAN_FORMAT ) );
	prestazioni_ricevuta_treestore->clear();
	capo_popup_connection.disconnect();
	prestazione_popup_connection.disconnect();
	selezione_capo_combobox->set_active ( -1 );
	selezione_prestazione_combobox->set_active ( -1 );
	capo_popup_connection = selezione_capo_combobox->signal_changed ().connect (sigc::mem_fun (this, &Controller::load_prestazione_popup_button) );
	prestazione_popup_connection = selezione_prestazione_combobox->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_selezione_prestazione_popup_changed) );
	totale_ricevuta_label->set_text( "0,0" );
	acconto_ricevuta_entry->set_text( "0,0" );
	acconto_ricevuta_entry->set_sensitive (true);
	nonpagato_radiobutton->set_active (true);
	stampa_ricevuta_checkbutton->set_active (true);
	new_ricevuta_window->present ();
	cliente_ricevuta_entry->grab_focus();
}

void Controller::
on_new_prestazione_action ( void )
{
	main_notebook->set_current_page (PAGINA_PRESTAZIONI);
	prestazioni_treeselection->unselect_all ();
	capo_prestazione_entry->set_text ( "" );
	descrizione_prestazione_entry->set_text ( "" );
	prezzo_prestazione_entry->set_text ( "" );
	new_prestazione_window->present ();
	capo_prestazione_entry->grab_focus();
}

void Controller::
on_new_cliente_action ( void )
{
	main_notebook->set_current_page (PAGINA_CLIENTI);
	clienti_treeselection->unselect_all ();
	nome_cliente_entry->set_text ( "" );
	telefono_cliente_entry->set_text ( "" );
	new_cliente_window->present ();
	nome_cliente_entry->grab_focus();
}

void Controller::
on_edit_item_action ( void )
{
	vector<Gtk::TreePath> selected;
	switch ( main_notebook_page )
	{
		case PAGINA_RICEVUTE:
			selected = ricevute_treeselection->get_selected_rows ();
			ricevute_treeview_edit_selected_rows ( selected );
			break;
		case PAGINA_PRESTAZIONI:
			selected = prestazioni_treeselection->get_selected_rows ();
			prestazioni_treeview_edit_selected_rows ( selected );
			break;
		case PAGINA_CLIENTI:
			selected = clienti_treeselection->get_selected_rows ();
			clienti_treeview_edit_selected_rows ( selected );
			break;
	}
}

void Controller::
on_remove_item_action ( void )
{
	Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, "Vuoi eliminare definitivamente gli elementi selezionati?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
	int res_id = alert_dialog->run();
	delete alert_dialog;
	if ( res_id == Gtk::RESPONSE_YES )
	{
		vector<Gtk::TreePath> selected;
		switch ( main_notebook_page )
		{
			case PAGINA_RICEVUTE:
				selected = ricevute_treeselection->get_selected_rows ();
				ricevute_treeview_remove_selected_rows ( selected );
				salva_menuitem->set_sensitive ( true );
				ricevute_changed = true;
				break;
			case PAGINA_PRESTAZIONI:
				selected = prestazioni_treeselection->get_selected_rows ();
				prestazioni_treeview_remove_selected_rows ( selected );
				salva_menuitem->set_sensitive ( true );
				prestazioni_changed = true;
				break;
			case PAGINA_CLIENTI:
				selected = clienti_treeselection->get_selected_rows ();
				clienti_treeview_remove_selected_rows ( selected );
				salva_menuitem->set_sensitive ( true );
				clienti_changed = true;
				break;
		}
	}
}

void Controller::
on_stampa_chiusura_cassa_action ( void )
{
	Glib::ustring str = "<tt>";
	Glib::ustring str2;
	time_t inizio, fine;
	float totale_lordo = 0.0;
	float totale_sospeso = 0.0;
	float totale_netto = 0.0;
	size_t line = 32;
	calcola_periodo_tempo (inizio, fine, 0);
	set<Ricevuta>::const_iterator iter_r = ricevute->begin();
	set<Ricevuta>::const_iterator end_r = ricevute->end();
	str += Ricevuta::get_string_data(time(NULL), HUMAN_FORMAT) + "\n";
	while ( iter_r != end_r )
	{
		// lavoro accettato il giorno corrente
		if ( iter_r->get_data_accettazione () >= inizio && iter_r->get_data_accettazione () <= fine && !iter_r->is_consegnato ())
		{
			str2 += get_stampa_prestazioni ( iter_r, line );
			totale_lordo += iter_r->get_totale();
			totale_sospeso += iter_r->get_totale_da_pagare ();
			totale_netto += iter_r->get_acconto ();
		}
		// lavoro consegnato il giorno corrente
		if ( iter_r->is_consegnato () && iter_r->get_data_ritiro() >= inizio && iter_r->get_data_ritiro() <= fine )
		{
			str2 += get_stampa_prestazioni ( iter_r, line );
			totale_lordo += iter_r->get_totale();
			totale_netto += iter_r->get_totale_da_pagare ();
		}
		iter_r++;
	}
	str += "________________________________\n\n";
	str += Ricevuta::get_formatted_line (Glib::ustring("Incasso lordo"), "€ " + Prestazione::get_valuta_string(totale_lordo), line);
	str += Ricevuta::get_formatted_line (Glib::ustring("Incasso in sospeso"), "€ " + Prestazione::get_valuta_string(totale_sospeso), line);
	str += Ricevuta::get_formatted_line (Glib::ustring("Incasso netto"), "€ " + Prestazione::get_valuta_string(totale_netto), line);
	str += str2;
	str += "________________________________\n\n";
	str += Ricevuta::get_formatted_line (Glib::ustring("Incasso netto"), "€ " + Prestazione::get_valuta_string(totale_netto), line);
	str += "</tt>";
	print_or_preview_chiusura (Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, str);
}

void Controller::
on_save_action ( void )
{
	if ( should_save () )
	{
		bool rc, rp, rr;
		rc = rp = rr = true;
		if ( should_save_clienti () )
			rc = save_data ( get_clienti_file_path (), SAVE_CLIENTI );
		if ( should_save_prestazioni () )
			rp = save_data ( get_prestazioni_file_path (), SAVE_PRESTAZIONI );
		if ( should_save_ricevute () )
			rr = save_data ( get_ricevute_file_path (), SAVE_RICEVUTE );
		if ( rc && rp && rr )
			salva_menuitem->set_sensitive(false);
	}
}

void Controller::
on_page_setup_action ( void )
{
	m_refPageSetup = Gtk::run_page_setup_dialog (*main_window, m_refPageSetup, m_refSettings);
	m_refPageSetup->save_to_key_file ( *printer_keyfile );
	ofstream outfile ( page_setup_path.c_str(), ios_base::out );
	if ( !outfile )
		cerr << "ERRORE! on_page_setup_action():: unable to open file \"" << page_setup_path << "\"" << endl;
	else
	{
		outfile << printer_keyfile->to_data ();
		outfile.close();
	}
}

void Controller::
on_print_ricevuta_action ( void )
{
	vector<Gtk::TreeRowReference> sel_ref;
	vector<Gtk::TreePath> selected = ricevute_treeselection->get_selected_rows ();
	Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
	get_treeview_row_reference ( selected, ricevute_treemodel, sel_ref );
	vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
	vector<Gtk::TreeRowReference>::iterator sr_end = sel_ref.end();
	while ( sr_iter != sr_end )
	{
		Gtk::TreeModel::iterator it_rem = ricevute_treemodel->get_iter ( sr_iter->get_path () );
		set<Ricevuta>::iterator it = get_ricevuta_iterator ( *it_rem );
		if ( it != ricevute->end() )
		{
			print_or_preview_ricevuta(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, it->get_ricevuta_string (preferenze.get_stampa_numero_ricevuta ()));
		}
		else
			cerr << "ERRORE! on_print_ricevuta_action():: non trovo la ricevuta" << endl;
		sr_iter++;
	}
}

void Controller::
on_print_etichette_action ( void )
{
	vector<Gtk::TreeRowReference> sel_ref;
	vector<Gtk::TreePath> selected = ricevute_treeselection->get_selected_rows ();
	Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
	get_treeview_row_reference ( selected, ricevute_treemodel, sel_ref );
	vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
	vector<Gtk::TreeRowReference>::iterator sr_end = sel_ref.end();
	while ( sr_iter != sr_end )
	{
		Gtk::TreeModel::iterator it_rem = ricevute_treemodel->get_iter ( sr_iter->get_path () );
		set<Ricevuta>::iterator it = get_ricevuta_iterator ( *it_rem );
		if ( it != ricevute->end() )
		{
			const list<Capo>* capi = it->get_const_capi();
			list<Capo>::const_iterator iter_cp = capi->begin();
			list<Capo>::const_iterator end_cp = capi->end();
			while ( iter_cp != end_cp)
			{
				print_or_preview_etichetta (Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, it->get_etichetta_string (iter_cp, preferenze.get_stampa_numero_ricevuta ()));
				iter_cp++;
			}
		}
		else
			cerr << "ERRORE! on_print_etichette_action():: non trovo la ricevuta" << endl;
		sr_iter++;
	}
}

void Controller::
on_quit_app_action ( void )
{
	this_app->quit();
}

void Controller::
on_preferenze_action ( void )
{
	intestazione_textbuffer->set_text (preferenze.get_intestazione_ricevuta ());
	saluto_textbuffer->set_text (preferenze.get_saluto_ricevuta ());
	eliminazione_ricevute_combobox->set_active (preferenze.get_eliminazione_ricevute ());
	azzeramento_numero_combobox->set_active (preferenze.get_azzeramento_numero ());
	salvataggio_uscita_combobox->set_active (preferenze.get_salvataggio_automatico ());
	stampa_numero_ricevuta_checkbutton->set_active (preferenze.get_stampa_numero_ricevuta ());
	visualizza_numero_ricevuta_checkbutton->set_active(preferenze.get_visualizza_numero_ricevuta ());
	preferenze_window->show();
}

void Controller::
on_visualizza_action ( const unsigned short val )
{
	main_notebook->set_current_page (val);
}

void Controller::
on_about_app_action ( void )
{
	Gtk::AboutDialog *about_dialog;
	Glib::RefPtr<Gdk::Pixbuf> _logo = main_window->get_icon ();
	about_dialog = new Gtk::AboutDialog ();
	about_dialog->set_program_name ( Glib::ustring ( "LiberAcus" ) );
	about_dialog->set_version ( Glib::ustring ( "2.0 (141)" ) );
	about_dialog->set_copyright ( Glib::ustring ( "Copyright © 2013, 2014 Massimiliano Maniscalco" ) );
	about_dialog->set_comments ( Glib::ustring ( "LiberAcus è un software libero ( GPLv3 )" ) );
	about_dialog->set_website ( Glib::ustring ( "https://code.google.com/p/liberacus/" ) );
	about_dialog->set_website_label ( Glib::ustring ( "sito web del progetto" ) );
	about_dialog->set_license_type ( Gtk::LICENSE_GPL_3_0 );
	about_dialog->set_logo ( _logo );
	about_dialog->signal_response ().connect (sigc::bind<Gtk::AboutDialog*>( sigc::mem_fun (this, &Controller::on_about_response), about_dialog ) );
	about_dialog->run ();
}

void Controller::
on_about_response ( int response_id, Gtk::AboutDialog *about_dialog )
{
	about_dialog->hide ();
	delete about_dialog;
}

void Controller::
on_treeview_clicked ( GdkEventButton *event )
{
	if ( event->button == 1 && event->type == GDK_2BUTTON_PRESS )
	{
		vector<Gtk::TreePath> selected;
		switch ( main_notebook_page )
		{
			case PAGINA_RICEVUTE:
				selected = ricevute_treeselection->get_selected_rows ();
				ricevute_treeview_edit_selected_rows ( selected );
				break;
			case PAGINA_PRESTAZIONI:
				selected = prestazioni_treeselection->get_selected_rows ();
				prestazioni_treeview_edit_selected_rows ( selected );
				break;
			case PAGINA_CLIENTI:
				selected = clienti_treeselection->get_selected_rows ();
				clienti_treeview_edit_selected_rows ( selected );
				break;
		}
	}
	if ( event->button == 3 && event->type == GDK_BUTTON_PRESS )
	{
		switch ( main_notebook_page )
		{
			case PAGINA_RICEVUTE:
				ricevute_context_menu->popup (event->button, event->time);
				break;
			case PAGINA_PRESTAZIONI:
			case PAGINA_CLIENTI:
				generic_context_menu->popup (event->button, event->time);
				break;
		}
	}
}

void Controller::
aggiorna_pagina_calendario ( void )
{
	float totale;
	struct tm *data_ora;
	time_t tempo = time(NULL);
	data_ora = localtime ( &tempo );
	int oggi = data_ora->tm_wday;
	Gtk::Label *settimana_label[] = { calendario_lunedi_label, calendario_martedi_label, calendario_mercoledi_label, calendario_giovedi_label, calendario_venerdi_label, calendario_sabato_label };
	Gtk::Label *totale_label[] = { totale_lunedi_label, totale_martedi_label, totale_mercoledi_label, totale_giovedi_label, totale_venerdi_label, totale_sabato_label };
	Glib::RefPtr<Gtk::ListStore> settimana_liststore[] = { ricevute_lunedi_liststore, ricevute_martedi_liststore, ricevute_mercoledi_liststore, ricevute_giovedi_liststore, ricevute_venerdi_liststore, ricevute_sabato_liststore };
	int giorno = oggi;
	int giorni = 0;
	for (int i = 0; i < 6; i++)
	{
		if ( giorno == 0 )
		{
			giorno++;
			giorni++;
		}
		tempo = time(NULL) + ( giorni * UN_GIORNO);
		settimana_label[i]->set_text ( Ricevuta::get_string_data(tempo, LABEL_FORMAT) );
		totale = load_ricevute_del_giorno_in_treeview (settimana_liststore[i], tempo);
		totale_label[i]->set_text ( "Totale lordo €" + Prestazione::get_valuta_string(totale));
		giorno++;
		giorni++;
		if ( giorno > 6 )
		{
			giorno = 1;
			giorni++;
		}
	}
	load_riepilogo_prestazioni_in_treeview ();
}

float Controller::
load_ricevute_del_giorno_in_treeview ( Glib::RefPtr<Gtk::ListStore> liststore, time_t tempo )
{
	struct tm *data_ora;
	data_ora = localtime ( &tempo );
	int year = data_ora->tm_year;
	int month = data_ora->tm_mon;
	int day = data_ora->tm_mday;
	float totale = 0.0;
	liststore->clear();
	set<Ricevuta>::iterator iter = ricevute->begin();
	set<Ricevuta>::iterator iterEnd = ricevute->end();
	while (iter != iterEnd)
	{
		bool match = true;
		time_t tempo_rit = iter->get_data_ritiro ();
		data_ora = localtime ( &tempo_rit );
		if ( data_ora->tm_year != year )
			match = false;
		if ( match )
		{
			if ( data_ora->tm_mon != month )
				match = false;
			if ( match )
			{
				if ( data_ora->tm_mday != day )
					match = false;
				if ( match )
				{
					Gtk::TreeModel::iterator iterTree = liststore->append();
					Gtk::TreeModel::Row row = *iterTree;
					row[ricevute_giorno_listmodel->numero] = iter->get_numero_string ();
					row[ricevute_giorno_listmodel->cliente] = iter->get_nome_cliente ();
					row[ricevute_giorno_listmodel->urgente] = iter->is_urgente ();
					row[ricevute_giorno_listmodel->data_accettazione] = Ricevuta::get_string_data(iter->get_data_accettazione (), HUMAN_FORMAT);
					totale += iter->get_totale();
				}
			}
		}
		iter++;
	}
	return totale;
}

void Controller::
on_ricevute_del_giorno_treeselection_changed ( const short sender )
{
	Glib::RefPtr<Gtk::TreeSelection> settimana_selection[] = { ricevute_lunedi_treeselection, ricevute_martedi_treeselection, ricevute_mercoledi_treeselection, ricevute_giovedi_treeselection, ricevute_venerdi_treeselection, ricevute_sabato_treeselection };
	Gtk::TreeView* settimana_treeview[] = { ricevute_lunedi_treeview, ricevute_martedi_treeview, ricevute_mercoledi_treeview, ricevute_giovedi_treeview, ricevute_venerdi_treeview, ricevute_sabato_treeview };
	if ( settimana_selection[sender]->count_selected_rows () > 0 )
	{
		for (short i = 0; i < 6; i++)
		{
			if ( i != sender )
				settimana_selection[i]->unselect_all();
		}
		vector<Gtk::TreeRowReference> sel_ref;
		Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = settimana_treeview[sender]->get_model ();
		get_treeview_row_reference ( settimana_selection[sender]->get_selected_rows(), ricevute_treemodel, sel_ref );
		vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
		vector<Gtk::TreeRowReference>::iterator sr_end = sel_ref.end();
		if ( sr_iter != sr_end )
		{
			Gtk::TreeModel::iterator it_s = ricevute_treemodel->get_iter ( sr_iter->get_path () );
			Gtk::TreeModel::Row row = *it_s;
			Ricevuta temp;
			temp.set_numero ( row[ricevute_giorno_listmodel->numero] );
			temp.set_data_accettazione ( parse_data_string(row[ricevute_giorno_listmodel->data_accettazione]) );
			set<Ricevuta>::iterator it =  ricevute->find(temp);
			aggiorna_dettagli_ricevuta_calendario ( *it );
		}
	}
	else
	{
		calendario_dettaglio_numero_label->set_text (" ");
		calendario_dettaglio_cliente_label->set_text (" ");
		calendario_dettaglio_accettazione_label->set_text (" ");
		calendario_dettaglio_ritiro_label->set_text (" ");
		calendario_dettaglio_acconto_label->set_text (" ");
		calendario_dettaglio_totale_label->set_text (" ");
		calendario_dettaglio_prestazioni_treestore->clear();
	}
}

void Controller::
aggiorna_dettagli_ricevuta_calendario(const Ricevuta &rcvt)
{
	calendario_dettaglio_numero_label->set_text (rcvt.get_numero_string ());
	calendario_dettaglio_cliente_label->set_text (rcvt.get_nome_cliente ());
	calendario_dettaglio_accettazione_label->set_text (Ricevuta::get_string_data(rcvt.get_data_accettazione (), HUMAN_FORMAT));
	calendario_dettaglio_ritiro_label->set_text (Ricevuta::get_string_data(rcvt.get_data_ritiro (), HUMAN_FORMAT));
	calendario_dettaglio_acconto_label->set_text (Prestazione::get_valuta_string(rcvt.get_acconto ()));
	calendario_dettaglio_totale_label->set_text (Prestazione::get_valuta_string(rcvt.get_totale()));
	calendario_dettaglio_prestazioni_treestore->clear();
	const list<Capo>* capi = rcvt.get_const_capi ();
	list<Capo>::const_iterator iter = capi->begin();
	list<Capo>::const_iterator iterEnd = capi->end();
	while (iter != iterEnd)
	{
		// utilizza una variabile bool per verificare se tutte le prestazioni sono completate
		bool tutte_complete = true;
		Gtk::TreeModel::iterator iterTree = calendario_dettaglio_prestazioni_treestore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_ricevuta_treemodel->numero] = iter->get_numero_string ();
		row[prestazioni_ricevuta_treemodel->capo] = iter->get_capo ();
		const list<Prestazione>* prestazioni_capo = iter->get_const_prestazioni ();
		list<Prestazione>::const_iterator iter_prst = prestazioni_capo->begin();
		list<Prestazione>::const_iterator end_prst = prestazioni_capo->end();
		while (iter_prst != end_prst)
		{
			Gtk::TreeModel::iterator iterRowChild = calendario_dettaglio_prestazioni_treestore->append(row.children());
			Gtk::TreeModel::Row childRow = *iterRowChild;
			childRow[prestazioni_ricevuta_treemodel->descrizione] = iter_prst->get_descrizione ();
			childRow[prestazioni_ricevuta_treemodel->prezzo] = Prestazione::get_valuta_string ( iter_prst->get_prezzo() );
			bool completata = iter_prst->get_completata ();
			childRow[prestazioni_ricevuta_treemodel->completata] = completata;
			
			// se tutte_complete diventa false, non verrà più modificata
			if (tutte_complete)
				tutte_complete = completata ? true : false;
			iter_prst++;
		}
		row[prestazioni_ricevuta_treemodel->completata] = tutte_complete;
		iter++;
	}
	calendario_dettaglio_prestazioni_treeview->expand_all ();
}

/**
 * funzione chiamata quando si cambio lo stato del pulsante di spunta "completata"
 * se viene modificato il pulsante corrispondente al capo, tutte le prestazioni in esso contenute verranno modificate
 * */
void Controller::
on_calendario_prestazione_completa_toggled( const Glib::ustring &path )
{
	Ricevuta temp;
	Gtk::TreeModel::Path tm_path = Gtk::TreeModel::Path ( path );
	temp.set_numero ( atoi( calendario_dettaglio_numero_label->get_text().c_str() ) );
	temp.set_data_accettazione ( parse_data_string ( calendario_dettaglio_accettazione_label->get_text() ) );

	// cerca la ricevuta
	set<Ricevuta>::iterator iter = ricevute->find(temp);
	if ( iter != ricevute->end() )
	{
		// crea una copia della ricevuta trovata
		temp = *iter;
		Glib::RefPtr<Gtk::TreeModel> prestazioni_treemodel = calendario_dettaglio_prestazioni_treeview->get_model ();
		Gtk::TreeModel::iterator iterTree = prestazioni_treemodel->get_iter ( path );
		Gtk::TreeModel::Row row = *iterTree;
		unsigned int numero = atoi(Glib::ustring(row[prestazioni_ricevuta_treemodel->numero]).c_str());
		Glib::ustring capo_str = row[prestazioni_ricevuta_treemodel->capo];
		Glib::ustring descr_str = row[prestazioni_ricevuta_treemodel->descrizione];
		bool prestazione_toggled = false;
		if (capo_str == Glib::ustring(""))
		{
			// è stato cambiato lo stato di una prestazione
			prestazione_toggled = true;
			
			// risale al capo di appartenenza della prestazione
			tm_path.up();
			Gtk::TreeModel::iterator capo_iter = prestazioni_treemodel->get_iter ( tm_path );
			Gtk::TreeModel::Row capo_row = *capo_iter;
			numero = atoi(Glib::ustring(capo_row[prestazioni_ricevuta_treemodel->numero]).c_str());
			capo_str = capo_row[prestazioni_ricevuta_treemodel->capo];
		}
		// crea un capo come modello da ricercare
		Capo cp = Capo (capo_str, numero);

		// prendi i capi della ricevuta
		list<Capo>* capi_ricevuta = temp.get_capi();

		// trova il capo uguale a quello modello
		list<Capo>::iterator found_c = find(capi_ricevuta->begin(), capi_ricevuta->end(), cp);
		if (found_c != capi_ricevuta->end())
		{
			// usa una variabile bool per sapere se la modifica è andata a buon fine
			bool risultato = false;
			
			// prende le prestazioni del capo
			list<Prestazione>* prst_capo = found_c->get_prestazioni ();

			// controlla se deve modificare una sola prestazione o tutte le prestazioni del capo
			if (prestazione_toggled)
			{
				// crea una prestazione modello
				Prestazione prst = Prestazione (capo_str, descr_str, 0.0);

				// trova la prestazione uguale a quella modello
				list<Prestazione>::iterator found_p = find(prst_capo->begin(), prst_capo->end(), prst);
				if (found_p != prst_capo->end())
				{
					found_p->set_completata (row[prestazioni_ricevuta_treemodel->completata]);
					risultato = true;
				}
				else
					cerr << "ERRORE! on_calendario_prestazione_completa_toggled():: non trovo la prestazione" << endl;
			}
			else
			{
				list<Prestazione>::iterator iter_prst = prst_capo->begin();
				list<Prestazione>::iterator end_prst = prst_capo->end();
				while (iter_prst != end_prst)
				{
					iter_prst->set_completata (row[prestazioni_ricevuta_treemodel->completata]);
					iter_prst++;
				}
				risultato = true;
			}

			// verifica se le modifiche sono andate a buon fine
			if (risultato)
			{
				aggiorna_dettagli_ricevuta_calendario (temp);
				
				// sostituisce la ricevuta originale con la copia modificata
				replace_items(ricevute, iter, temp);
				ricevute_changed = true;
				salva_menuitem->set_sensitive(true);
				load_riepilogo_prestazioni_in_treeview();
			}
		}
		else
			cerr << "ERRORE! on_calendario_prestazione_completa_toggled():: non trovo il capo" << endl;
	}
	else
		cerr << "ERRORE! on_calendario_prestazione_completa_toggled():: non trovo la ricevuta" << endl;
}

void Controller::
load_riepilogo_prestazioni_in_treeview ( void )
{
	struct tm *data_ora;
	time_t inizio = time(NULL);
	data_ora = localtime ( &inizio );
	data_ora->tm_hour = 17;
	data_ora->tm_min = 30;
	data_ora->tm_sec = 0;
	inizio = mktime(data_ora);
	time_t fine = time(NULL) + (6 * UN_GIORNO);
	list<Prestazione> *riepilogo = new list<Prestazione> ();
	calendario_riepilogo_prestazioni_treestore->clear();
	set<Ricevuta>::iterator iter_r = ricevute->begin();
	set<Ricevuta>::iterator iter_rEnd = ricevute->end();
	while (iter_r != iter_rEnd)
	{
		if ( !iter_r->is_consegnato () )
		{
			if ( iter_r->get_data_ritiro () >= inizio && iter_r->get_data_ritiro () <= fine )
			{
				const list<Capo>* capi = iter_r->get_const_capi ();
				list<Capo>::const_iterator iter_c = capi->begin();
				list<Capo>::const_iterator end_c = capi->end();
				while (iter_c != end_c)
				{
					const list<Prestazione>* prestazioni_capo = iter_c->get_const_prestazioni ();
					list<Prestazione>::const_iterator iter_p = prestazioni_capo->begin ();
					list<Prestazione>::const_iterator end_p = prestazioni_capo->end ();
					while (iter_p != end_p)
					{
						if ( !iter_p->get_completata () )
						{
							list<Prestazione>::iterator it_riep = find (riepilogo->begin(), riepilogo->end(), *iter_p);
							if ( it_riep != riepilogo->end() )
								it_riep->incrementa_quantita ( iter_p->get_quantita () );
							else
								riepilogo->push_back (*iter_p);
						}
						iter_p++;
					}
					iter_c++;
				}
			}
		}
		iter_r++;
	}
	list<Prestazione>::iterator it_riep = riepilogo->begin();
	list<Prestazione>::iterator it_riep_end = riepilogo->end();
	while ( it_riep != it_riep_end )
	{
		Gtk::TreeModel::iterator iterTree = calendario_riepilogo_prestazioni_treestore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_ricevuta_treemodel->capo] = it_riep->get_capo ();
		row[prestazioni_ricevuta_treemodel->descrizione] = it_riep->get_descrizione ();
		it_riep++;
	}
	delete riepilogo;
}

void Controller::
load_ricevute_in_treeview ( bool filtro )
{
	ricevute_liststore->clear();
	set<Ricevuta>::iterator iter = ricevute->begin();
	set<Ricevuta>::iterator iterEnd = ricevute->end();
	while (iter != iterEnd)
	{
		Gtk::TreeModel::iterator iterTree = ricevute_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[ricevute_listmodel->numero] = iter->get_numero_string ();
		row[ricevute_listmodel->cliente] = iter->get_nome_cliente ();
		row[ricevute_listmodel->data_accettazione] = Ricevuta::get_string_data ( iter->get_data_accettazione (), HUMAN_FORMAT );
		row[ricevute_listmodel->costo] = Prestazione::get_valuta_string ( iter->get_totale() );
		row[ricevute_listmodel->acconto] = Prestazione::get_valuta_string ( iter->get_acconto () );
		row[ricevute_listmodel->data_ritiro] = Ricevuta::get_string_data ( iter->get_data_ritiro (), HUMAN_FORMAT );
		row[ricevute_listmodel->urgente] = iter->is_urgente();
		row[ricevute_listmodel->consegnato] = iter->is_consegnato();
		iter++;
	}
}

set<Ricevuta>::iterator Controller::
get_ricevuta_iterator ( Gtk::TreeModel::Row row )
{
	set<Ricevuta>::iterator it;
	Ricevuta temp;
	temp.set_numero ( row[ricevute_listmodel->numero] );
	temp.set_data_accettazione ( parse_data_string(row[ricevute_listmodel->data_accettazione]) );
	it = ricevute->find(temp);
	return it;
}

void Controller::
ricevute_treeview_remove_selected_rows ( const vector<Gtk::TreePath> &sel )
{
	Glib::ustring messaggio;
	vector<Gtk::TreeRowReference> sel_ref;
	Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
	get_treeview_row_reference ( sel, ricevute_treemodel, sel_ref );
	vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
	vector<Gtk::TreeRowReference>::iterator sr_end = sel_ref.end();
	while ( sr_iter != sr_end )
	{
		Gtk::TreeModel::iterator it_rem = ricevute_treemodel->get_iter ( sr_iter->get_path () );
		set<Ricevuta>::iterator it = get_ricevuta_iterator ( *it_rem );
		if ( it != ricevute->end() )
		{
			ricevute->erase ( it );
			ricevute_liststore->erase ( it_rem );
		}
		else
			cerr << "ERRORE! ricevute_treeview_remove_selected_rows():: non trovo la ricevuta" << endl;
		sr_iter++;
	}
	main_statusbar->pop ( stbrItemSelId );
	if ( sel.size() == 1 )
		messaggio.append ( Glib::ustring::compose( "Una ricevuta eliminata, %1 ricevute nell'archivio.", Glib::ustring::format( ricevute->size() ) ) );
	else
		messaggio.append ( Glib::ustring::compose( "%1 ricevute eliminate, %2 ricevute nell'archivio.", Glib::ustring::format( sel.size() ), Glib::ustring::format( ricevute->size() ) ) );
	main_statusbar->push ( messaggio, stbrItemSelId );
}

void Controller::
ricevute_treeview_edit_selected_rows ( const vector<Gtk::TreePath> &sel )
{
	int nr_sel = ricevute_treeselection->count_selected_rows ();
	vector<Gtk::TreeRowReference> sel_ref;
	Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
	get_treeview_row_reference ( sel, ricevute_treemodel, sel_ref );
	if ( nr_sel > 0 )
	{
		vector<Gtk::TreePath>::const_iterator iter = sel.begin ();
		Gtk::TreeModel::iterator iter_view = ricevute_treemodel->get_iter ( *iter );
		Gtk::TreeModel::Row row = *iter_view;
		if (preferenze.get_visualizza_numero_ricevuta ())
		{
			Glib::ustring numero = row[ricevute_listmodel->numero];
			new_ricevuta_window->set_title (Glib::ustring ( "Ricevuta numero: " ) + numero );
		}
		else
			new_ricevuta_window->set_title (Glib::ustring ( "Ricevuta" ) );
		cliente_ricevuta_entry->set_text ( row[ricevute_listmodel->cliente] );
		selezione_capo_combobox->set_active ( -1 );
		selezione_prestazione_combobox->set_active ( -1 );
		acconto_ricevuta_entry->set_text ( row[ricevute_listmodel->acconto] );
		stampa_ricevuta_checkbutton->set_active (false);
		urgente_ricevuta_checkbutton->set_active ( row[ricevute_listmodel->urgente] );
		if ( nr_sel > 1 )
		{
			data_accettazione_ricevuta_entry->set_text ( "selezione multipla" );
			cambia_data_ricevuta_button1->set_sensitive ( false );
			data_ritiro_ricevuta_entry->set_text ( "selezione multipla" );
			cambia_data_ricevuta_button2->set_sensitive ( false );
			selezione_prestazione_combobox->set_sensitive ( false );
			totale_ricevuta_label->set_text ( "selezione multipla" );
		}
		else
		{
			data_accettazione_ricevuta_entry->set_text ( row[ricevute_listmodel->data_accettazione] );
			cambia_data_ricevuta_button1->set_sensitive ( true );
			data_ritiro_ricevuta_entry->set_text ( row[ricevute_listmodel->data_ritiro] );
			cambia_data_ricevuta_button2->set_sensitive ( true );
			selezione_prestazione_combobox->set_sensitive ( true );
			vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
			Gtk::TreeModel::iterator it_r = ricevute_treemodel->get_iter ( sr_iter->get_path () );
			set<Ricevuta>::iterator it_rcvt = get_ricevuta_iterator ( *it_r );
			if ( it_rcvt != ricevute->end() )
			{
				const list<Capo>* capi = it_rcvt->get_const_capi ();
				load_prestazioni_ricevuta_in_treeview ( capi->begin(), capi->end() );
				totale_ricevuta_label->set_text ( Prestazione::get_valuta_string ( it_rcvt->get_totale() ) );
				if ( it_rcvt->is_pagato () )
				{
					acconto_ricevuta_entry->set_sensitive(false);
					pagato_radiobutton->set_active(true);
				}
				else
				{
					acconto_ricevuta_entry->set_sensitive(true);
					nonpagato_radiobutton->set_active(true);
				}
			}
			else
				cerr << "ERRORE! ricevute_treeview_edit_selected_rows():: non trovo la ricevuta" << endl;
		}
		new_ricevuta_window->present ();
	}
}

void Controller::
on_ricevuta_urgente_toggled ( const Glib::ustring &path )
{
	Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
	Gtk::TreeModel::iterator iterTree = ricevute_treemodel->get_iter ( path );
	Gtk::TreeModel::Row row = *iterTree;
	set<Ricevuta>::iterator it = get_ricevuta_iterator (row);
	if ( it != ricevute->end() )
	{
		Ricevuta rcvt = *it;
		rcvt.set_urgente (row[ricevute_listmodel->urgente]);
		replace_items (ricevute, it, rcvt);
		ricevute_changed = true;
		salva_menuitem->set_sensitive(true);
	}
	else
		cerr << "ERRORE! on_ricevuta_urgente_toggled():: non trovo la ricevuta" << endl;
}

void Controller::
on_ricevuta_consegnato_toggled ( const Glib::ustring &path )
{
	Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
	Gtk::TreeModel::iterator iterTree = ricevute_treemodel->get_iter ( path );
	Gtk::TreeModel::Row row = *iterTree;
	set<Ricevuta>::iterator it = get_ricevuta_iterator (row);
	if ( it != ricevute->end() )
	{
		if (row[ricevute_listmodel->consegnato])
		{
			float pagare = it->get_totale_da_pagare ();
			Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, Glib::ustring::compose("Totale da pagare %1 euro. Vuoi contrassegnare la ricevuta selezionata come lavoro consegnato?", Prestazione::get_valuta_string( pagare ) ), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
			int res_id = alert_dialog->run();
			delete alert_dialog;
			if ( res_id == Gtk::RESPONSE_YES )
			{
				Ricevuta rcvt = *it;
				rcvt.set_consegnato (row[ricevute_listmodel->consegnato]);
				rcvt.set_lavoro_completato ();
				rcvt.set_data_ritiro ( time(NULL) );
				replace_items (ricevute, it, rcvt);
				row[ricevute_listmodel->data_ritiro] = Ricevuta::get_string_data ( it->get_data_ritiro (), HUMAN_FORMAT );
				ricevute_changed = true;
				salva_menuitem->set_sensitive(true);
				on_items_treeselection_changed();
				main_statusbar->pop ( stbrItemSelId );
				main_statusbar->push ( Glib::ustring::compose( "Una ricevuta contrassegnata come lavoro consegnato, %1 ricevute nell'archivio.", Glib::ustring::format( ricevute->size() ) ), stbrItemSelId );
			}
			else
				row[ricevute_listmodel->consegnato] = false;
		}
		else
		{
			Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, Glib::ustring("Questa ricevuta risulta come lavoro già consegnato, vuoi contrassegnarla come lavoro non ancora consegnato?"), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
			int res_id = alert_dialog->run();
			delete alert_dialog;
			if ( res_id == Gtk::RESPONSE_YES )
			{
				Ricevuta rcvt = *it;
				rcvt.set_consegnato (row[ricevute_listmodel->consegnato]);
				replace_items (ricevute, it, rcvt);
				ricevute_changed = true;
				salva_menuitem->set_sensitive(true);
				on_items_treeselection_changed();
				main_statusbar->pop ( stbrItemSelId );
				main_statusbar->push ( Glib::ustring::compose( "Una ricevuta contrassegnata come lavoro non consegnato, %1 ricevute nell'archivio.", Glib::ustring::format( ricevute->size() ) ), stbrItemSelId );
			}
			else
				row[ricevute_listmodel->consegnato] = true;
		}
	}
	else
		cerr << "ERRORE! on_ricevuta_pagato_toggled():: non trovo la ricevuta" << endl;
}

void Controller::
load_prestazioni_in_treeview ( void )
{
	prestazioni_liststore->clear();
	set<Prestazione>::iterator iter = prestazioni->begin();
	set<Prestazione>::iterator iterEnd = prestazioni->end();
	while (iter != iterEnd)
	{
		Gtk::TreeModel::iterator iterTree = prestazioni_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_listmodel->capo] = iter->get_capo ();
		row[prestazioni_listmodel->descrizione] = iter->get_descrizione ();
		row[prestazioni_listmodel->prezzo] = Prestazione::get_valuta_string ( iter->get_prezzo() );
		iter++;
	}
}

set<Prestazione>::iterator Controller::
get_prestazione_iterator ( Gtk::TreeModel::Row row )
{
	set<Prestazione>::iterator it;
	Prestazione temp (row[prestazioni_listmodel->capo], row[prestazioni_listmodel->descrizione], 0.0);
	it = prestazioni->find(temp);
	return it;
}

void Controller::
prestazioni_treeview_remove_selected_rows ( const vector<Gtk::TreePath> &sel )
{
	Glib::ustring messaggio;
	vector<Gtk::TreeRowReference> sel_ref;
	Glib::RefPtr<Gtk::TreeModel> prestazioni_treemodel = prestazioni_treeview->get_model ();
	get_treeview_row_reference ( sel, prestazioni_treemodel, sel_ref );
	vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
	vector<Gtk::TreeRowReference>::iterator sr_end = sel_ref.end();
	while ( sr_iter != sr_end )
	{
		Gtk::TreeModel::iterator it_rem = prestazioni_treemodel->get_iter ( sr_iter->get_path () );
		set<Prestazione>::iterator it = get_prestazione_iterator ( *it_rem );
		if ( it != prestazioni->end() )
		{
			if ( mappa_capi->count(it->get_capo ()) > 1 )
				mappa_capi->at(it->get_capo ()) -= 1;
			else
			{
				mappa_capi->erase(it->get_capo ());
				load_capo_popup_button ();
				load_capi_in_prestazione_completion ();
			}
			prestazioni->erase(it);
			prestazioni_liststore->erase ( it_rem );
		}
		else
			cerr << "ERRORE! prestazioni_treeview_remove_selected_rows():: non trovo la prestazione" << endl;
		sr_iter++;
	}
	main_statusbar->pop ( stbrItemSelId );
	if ( sel.size() == 1 )
		messaggio.append ( Glib::ustring::compose( "Una prestazione eliminata, %1 prestazioni nel preziario.", Glib::ustring::format( prestazioni->size() ) ) );
	else
		messaggio.append ( Glib::ustring::compose( "%1 prestazioni eliminate, %2 prestazioni nel preziario.", Glib::ustring::format( sel.size() ), Glib::ustring::format( prestazioni->size() ) ) );
	main_statusbar->push ( messaggio, stbrItemSelId );
}

void Controller::
prestazioni_treeview_edit_selected_rows ( const vector<Gtk::TreePath> &sel )
{
	int nr_sel = prestazioni_treeselection->count_selected_rows ();
	Glib::RefPtr<Gtk::TreeModel> prestazioni_treemodel = prestazioni_treeview->get_model ();
	if ( nr_sel > 0 )
	{
		vector<Gtk::TreePath>::const_iterator iter = sel.begin ();
		Gtk::TreeModel::iterator iter_view = prestazioni_treemodel->get_iter ( *iter );
		Gtk::TreeModel::Row row = *iter_view;
		prezzo_prestazione_entry->set_text ( row[prestazioni_listmodel->prezzo] );
		if ( nr_sel > 1 )
		{
			capo_prestazione_entry->set_text ( "selezione multipla" );
			capo_prestazione_entry->set_sensitive ( false );
			descrizione_prestazione_entry->set_text ( "selezione multipla" );
			descrizione_prestazione_entry->set_sensitive ( false );
		}
		else
		{
			capo_prestazione_entry->set_text ( row[prestazioni_listmodel->capo] );
			capo_prestazione_entry->set_sensitive ( true );
			descrizione_prestazione_entry->set_text ( row[prestazioni_listmodel->descrizione] );
			descrizione_prestazione_entry->set_sensitive ( true );
		}
		new_prestazione_window->present ();
	}
}

void Controller::
load_clienti_in_treeview ( void )
{
	clienti_liststore->clear();
	set<Cliente>::iterator iter = clienti->begin();
	set<Cliente>::iterator iterEnd = clienti->end();
	while (iter != iterEnd)
	{
		Gtk::TreeModel::iterator iterTree = clienti_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[clienti_listmodel->nome] = iter->get_nome ();
		row[clienti_listmodel->telefono] = iter->get_telefono ();
		iter++;
	}
}

set<Cliente>::iterator Controller::
get_cliente_iterator ( Gtk::TreeModel::Row row )
{
	set<Cliente>::iterator it;
	Cliente temp;
	temp.set_nome ( row[clienti_listmodel->nome] );
	Glib::ustring telefono = row[clienti_listmodel->telefono];
	temp.set_telefono ( telefono );
	it = clienti->find(temp);
	return it;
}

void Controller::
clienti_treeview_remove_selected_rows ( const vector<Gtk::TreePath> &sel )
{
	Glib::ustring messaggio;
	vector<Gtk::TreeRowReference> sel_ref;
	Glib::RefPtr<Gtk::TreeModel> clienti_treemodel = clienti_treeview->get_model ();
	get_treeview_row_reference ( sel, clienti_treemodel, sel_ref );
	vector<Gtk::TreeRowReference>::iterator sr_iter = sel_ref.begin();
	vector<Gtk::TreeRowReference>::iterator sr_end = sel_ref.end();
	while ( sr_iter != sr_end )
	{
		Gtk::TreeModel::iterator it_rem = clienti_treemodel->get_iter ( sr_iter->get_path () );
		set<Cliente>::iterator it = get_cliente_iterator ( *it_rem );
		if ( it != clienti->end() )
		{
			clienti->erase (it);
			clienti_liststore->erase ( it_rem );
		}
		else
			cerr << "ERRORE! clienti_treeview_remove_selected_rows():: non trovo il cliente" << endl;
		sr_iter++;
	}
	main_statusbar->pop ( stbrItemSelId );
	if ( sel.size() == 1 )
		messaggio.append ( Glib::ustring::compose( "Un cliente eliminato, %1 clienti nell'archivio.", Glib::ustring::format( clienti->size() ) ) );
	else
		messaggio.append ( Glib::ustring::compose( "%1 clienti eliminati, %2 clienti nell'archivio.", Glib::ustring::format( sel.size() ), Glib::ustring::format( clienti->size() ) ) );
	main_statusbar->push ( messaggio, stbrItemSelId );
}

void Controller::
clienti_treeview_edit_selected_rows ( const vector<Gtk::TreePath> &sel )
{
	int nr_sel = clienti_treeselection->count_selected_rows ();
	Glib::RefPtr<Gtk::TreeModel> clienti_treemodel = clienti_treeview->get_model ();
	if ( nr_sel > 0 )
	{
		vector<Gtk::TreePath>::const_iterator iter = sel.begin ();
		Gtk::TreeModel::iterator iter_view = clienti_treemodel->get_iter ( *iter );
		Gtk::TreeModel::Row row = *iter_view;
		telefono_cliente_entry->set_text ( row[clienti_listmodel->telefono] );
		if ( nr_sel > 1 )
		{
			nome_cliente_entry->set_text ( "selezione multipla" );
			nome_cliente_entry->set_sensitive ( false );
		}
		else
		{
			nome_cliente_entry->set_text ( row[clienti_listmodel->nome] );
			nome_cliente_entry->set_sensitive ( true );
		}
		new_cliente_window->present ();
	}
}

void Controller::
aggiorna_pagina_resoconto ( void )
{
	time_t inizio, fine;
	calcola_periodo_tempo ( inizio, fine, selezione_periodo_combobox->get_active_row_number () );
	int numero_ricevute = 0;
	int numero_prestazioni = 0;
	int numero_clienti = 0;
	float incasso_totale = 0.0;
	list<Glib::ustring> *customers = new list<Glib::ustring> ();
	list<Prestazione> *works = new list<Prestazione> ();
	ricevute_resoconto_liststore->clear();
	set<Ricevuta>::iterator iter = ricevute->begin();
	set<Ricevuta>::iterator iterEnd = ricevute->end();
	while (iter != iterEnd)
	{
		if ( iter->get_data_accettazione () >= inizio && iter->get_data_accettazione () <= fine && iter->get_acconto () > 0.0 )
		{
			incasso_totale += iter->get_acconto ();
		}
		if ( iter->is_consegnato() && iter->get_data_ritiro() >= inizio && iter->get_data_ritiro() <= fine )
		{
			numero_ricevute++;
			incasso_totale += iter->get_totale_da_pagare ();
			Glib::ustring nome = iter->get_nome_cliente ();
			list<Glib::ustring>::iterator it_cl = find ( customers->begin(), customers->end(), nome );
			if ( it_cl == customers->end() )
				customers->push_back ( nome );
			const list<Capo>* capi_r = iter->get_const_capi ();
			list<Capo>::const_iterator iter_c = capi_r->begin();
			list<Capo>::const_iterator end_c = capi_r->end();
			while (iter_c != end_c)
			{
				const list<Prestazione>* prestazioni_r = iter_c->get_const_prestazioni ();
				list<Prestazione>::const_iterator iter_p = prestazioni_r->begin();
				list<Prestazione>::const_iterator end_p = prestazioni_r->end();
				while (iter_p != end_p)
				{
					list<Prestazione>::iterator found = find ( works->begin(), works->end(), *iter_p);
					if ( found == works->end() )
						works->push_back (*iter_p);
					else
						found->incrementa_quantita (iter_p->get_quantita () );
					iter_p++;
				}
				iter_c++;
			}
			Gtk::TreeModel::iterator iterTree = ricevute_resoconto_liststore->append();
			Gtk::TreeModel::Row row = *iterTree;
			row[ricevute_resoconto_listmodel->numero] = iter->get_numero_string ();
			row[ricevute_resoconto_listmodel->cliente] = iter->get_nome_cliente ();
			row[ricevute_resoconto_listmodel->totale] = Prestazione::get_valuta_string ( iter->get_totale() );
		}
		iter++;
	}
	list<Prestazione>::iterator iterP = works->begin();
	list<Prestazione>::iterator iterP_end = works->end();
	prestazioni_resoconto_liststore->clear();
	while ( iterP != iterP_end )
	{
		numero_prestazioni += iterP->get_quantita ();
		Gtk::TreeModel::iterator iterTree = prestazioni_resoconto_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_ricevuta_treemodel->numero] = Glib::ustring::format(iterP->get_quantita ());
		row[prestazioni_ricevuta_treemodel->capo] = iterP->get_capo ();
		row[prestazioni_ricevuta_treemodel->descrizione] = iterP->get_descrizione ();
		row[prestazioni_ricevuta_treemodel->prezzo] = Prestazione::get_valuta_string ( iterP->get_prezzo () );
		iterP++;
	}
	list<Glib::ustring>::iterator iterC = customers->begin();
	list<Glib::ustring>::iterator iterC_end = customers->end();
	clienti_resoconto_liststore->clear();
	while ( iterC != iterC_end )
	{
		Gtk::TreeModel::iterator iterTree = clienti_resoconto_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[clienti_listmodel->nome] = *iterC;
		iterC++;
	}
	resoconto_ricevute_emesse_label->set_text ( Glib::ustring::format( numero_ricevute ) );
	resoconto_prestazioni_effettuate_label->set_text ( Glib::ustring::format( numero_prestazioni ) );
	resoconto_clienti_serviti_label->set_text ( Glib::ustring::format( customers->size() ) );
	resoconto_incasso_totale_label->set_text ( Prestazione::get_valuta_string( incasso_totale ) );
	delete customers;
	delete works;
}

void Controller::
disconnect_capo_popup ( void )
{
	capo_popup_connection.disconnect();
}

void Controller::
reconnect_capo_popup ( void )
{
	capo_popup_connection = selezione_capo_combobox->signal_changed ().connect (sigc::mem_fun (this, &Controller::load_prestazione_popup_button) );
}
void Controller::
disconnect_prestazione_popup ( void )
{
	prestazione_popup_connection.disconnect();
}

void Controller::
reconnect_prestazione_popup ( void )
{
	prestazione_popup_connection = selezione_prestazione_combobox->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_selezione_prestazione_popup_changed) );
}

void Controller::
disconnect_prestazioni_ricevuta ( void )
{
	prestazioni_ricevuta_connection.disconnect();
}

void Controller::
reconnect_prestazioni_ricevuta ( void )
{
	prestazioni_ricevuta_connection = prestazioni_ricevuta_treeselection->signal_changed ().connect (sigc::mem_fun (this, &Controller::on_prestazioni_ricevuta_selection_changed) );
}

void Controller::
load_capo_popup_button ( void )
{
	disconnect_capo_popup ();
	selezione_capo_liststore->clear();
	map<Glib::ustring,int>::iterator iter_capi = mappa_capi->begin();
	map<Glib::ustring,int>::iterator end_capi = mappa_capi->end();
	while ( iter_capi != end_capi )
	{
		Gtk::TreeModel::iterator iter = selezione_capo_liststore->append();
		Gtk::TreeModel::Row row = *iter;
		row[button_popup_listmodel->column] = iter_capi->first;
		iter_capi++;
	}
	selezione_capo_liststore->set_sort_column ( 0, Gtk::SORT_ASCENDING );
	selezione_capo_combobox->set_active (-1);
	reconnect_capo_popup ();
}

void Controller::
load_prestazione_popup_button ( void )
{
	disconnect_prestazione_popup ();
	selezione_prestazione_liststore->clear();
	Glib::ustring capo = Glib::ustring ( "" );
	int indice = selezione_capo_combobox->get_active_row_number ();
	if ( indice >= 0 )
	{
		Gtk::TreeModel::iterator iter = selezione_capo_combobox->get_active ();
		Gtk::TreeModel::Row row = *iter;
		capo.assign(row[button_popup_listmodel->column]);
		set<Prestazione>::iterator iter_prestazioni = prestazioni->begin();
		set<Prestazione>::iterator end_prestazioni = prestazioni->end();
		while ( iter_prestazioni != end_prestazioni )
		{
			bool match = false;
			if ( iter_prestazioni->get_capo() == capo )
				match = true;
			if (  match )
			{
				Gtk::TreeModel::iterator iter = selezione_prestazione_liststore->append();
				Gtk::TreeModel::Row row = *iter;
				row[button_popup_listmodel->column] = iter_prestazioni->get_descrizione();
			}
			iter_prestazioni++;
		}
		selezione_prestazione_liststore->set_sort_column ( 0, Gtk::SORT_ASCENDING );
	}
	reconnect_prestazione_popup ();
}

void Controller::
load_clienti_in_ricevuta_completion ( void )
{
	nome_cliente_liststore->clear();
	set<Cliente>::iterator iter = clienti->begin();
	set<Cliente>::iterator iterEnd = clienti->end();
	while (iter != iterEnd)
	{
		Gtk::TreeModel::iterator iterTree = nome_cliente_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[button_popup_listmodel->column] = iter->get_nome ();
		iter++;
	}
}

void Controller::
on_trova_clienti_action ( void )
{
	load_clienti_in_finestra_suggerimento ();
	suggerimento_clienti_window->present ();
}

void Controller::
on_cambia_data_ricevuta_action ( Gtk::Button *sender )
{
	Glib::ustring data_ora_string;
	if ( sender == cambia_data_ricevuta_button1 )
	{
		calendario_window->set_title ("Accettazione");
		data_ora_string = data_accettazione_ricevuta_entry->get_text();
	}
	if ( sender == cambia_data_ricevuta_button2 )
	{
		calendario_window->set_title ("Ritiro");
		data_ora_string = data_ritiro_ricevuta_entry->get_text();
	}
	time_t tempo = parse_data_string (data_ora_string);
	struct tm *data_ora = localtime( &tempo );
	main_calendar->select_month (data_ora->tm_mon, data_ora->tm_year + 1900);
	main_calendar->select_day (data_ora->tm_mday);
	data_modificata_connection = main_calendar->signal_day_selected ().connect ( sigc::mem_fun (this, &Controller::on_data_modificata) );
	calendario_window->present ();
}

void Controller::
load_prestazioni_ricevuta_in_treeview ( list<Capo>::const_iterator iter, list<Capo>::const_iterator end )
{
	disconnect_prestazioni_ricevuta ();
	prestazioni_ricevuta_treestore->clear();
	while (iter != end)
	{
		Gtk::TreeModel::iterator iterTree = prestazioni_ricevuta_treestore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_ricevuta_treemodel->numero] = iter->get_numero_string();
		row[prestazioni_ricevuta_treemodel->capo] = iter->get_capo();
		const list<Prestazione>* prestazioni_capo = iter->get_const_prestazioni ();
		list<Prestazione>::const_iterator prst_iter = prestazioni_capo->begin();
		list<Prestazione>::const_iterator prst_end = prestazioni_capo->end();
		while (prst_iter != prst_end)
		{
			Gtk::TreeModel::iterator iterRowChild = prestazioni_ricevuta_treestore->append(row.children());
			Gtk::TreeModel::Row childRow = *iterRowChild;
			childRow[prestazioni_ricevuta_treemodel->descrizione] = prst_iter->get_descrizione();
			childRow[prestazioni_ricevuta_treemodel->prezzo] = Prestazione::get_valuta_string(prst_iter->get_prezzo());
			prst_iter++;
		}
		iter++;
	}
	reconnect_prestazioni_ricevuta ();
}

Gtk::TreeModel::Path Controller::
get_prestazione_ricevuta_selezionata ( void )
{
	vector<Gtk::TreePath> selected = prestazioni_ricevuta_treeselection->get_selected_rows ();
	vector<Gtk::TreeRowReference> selRef;
	Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_treemodel = prestazioni_ricevuta_treeview->get_model ();
	get_treeview_row_reference ( selected, prestazioni_ricevuta_treemodel, selRef );
	vector<Gtk::TreeRowReference>::iterator srIter = selRef.begin();
	return srIter->get_path();
}

/**
 * funziona chiamata quando cambia la selezione delle prestazioni nella finestra della ricevuta
 * aggiorna la selezione dei tasti popup dei capi e della prestazione
 * */
void Controller::
on_prestazioni_ricevuta_selection_changed ( void )
{
	// controlla se ci sono righe selezionate
	if ( prestazioni_ricevuta_treeselection->count_selected_rows () > 0 )
	{
		// attiva il tasto di rimozione dei capi o prestazioni
		rem_prestazione_ricevuta_button->set_sensitive (true);

		// trova l'iterator della riga selezionata
		Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
		Gtk::TreeModel::Path path = get_prestazione_ricevuta_selezionata ();
		Gtk::TreeModel::iterator iter_tree = prestazioni_ricevuta_model->get_iter (path);
		Gtk::TreeModel::Row row_tree = *iter_tree;

		// tenta di espandere la riga selezionata e verifica se è già espansa
		if (prestazioni_ricevuta_treeview->expand_row (path, false) || prestazioni_ricevuta_treeview->row_expanded(path))
		{
			// è stato selezionato un capo della ricevuta
			
			// aggiorna la selezione del tasto popup dei capi
			update_capo_popup_button (Glib::ustring(row_tree[prestazioni_ricevuta_treemodel->capo]));

			// aggiorna la selezione del tasto popup delle prestazioni
			update_prestazioni_popup_button (Glib::ustring(""));

			// disattiva il tasto di addizione di una nuova prestazione
			add_prestazione_ricevuta_button->set_sensitive (false);
		}
		else
		{
			// è stata selezionata una prestazione
			
			// risale alla riga genitore per trovare il capo di appartenenza
			path.up();
			Gtk::TreeModel::iterator parent_iter = prestazioni_ricevuta_model->get_iter(path);
			Gtk::TreeModel::Row parent_row = *parent_iter;

			// aggiorna la selezione del tasto popup dei capi
			update_capo_popup_button (Glib::ustring(parent_row[prestazioni_ricevuta_treemodel->capo]));

			// aggiorna la selezione del tasto popup delle prestazioni
			update_prestazioni_popup_button (Glib::ustring(row_tree[prestazioni_ricevuta_treemodel->descrizione]));

			// attiva il tasto di addizione di una nuova prestazione
			add_prestazione_ricevuta_button->set_sensitive (true);
		}
	}
	else
	{
		rem_prestazione_ricevuta_button->set_sensitive (false);
		add_prestazione_ricevuta_button->set_sensitive (false);
		update_capo_popup_button (Glib::ustring(""));
	}
}

/**
 * aggiorna la selezione del tasto popup dei capi con il capo passato come parametro
 * */
bool Controller::
update_capo_popup_button ( const Glib::ustring capo )
{
	Glib::ustring capo_button;
	bool result = false;
	if ( selezione_capo_combobox->get_active_row_number () >= 0 )
	{
		Gtk::TreeModel::iterator it_popup = selezione_capo_combobox->get_active ();
		Gtk::TreeModel::Row row_popup = *it_popup;
		capo_button = row_popup[button_popup_listmodel->column];
	}
	if ( capo != capo_button )
	{
		disconnect_capo_popup ();
		selezione_capo_combobox->set_active ( -1 );
		if ( capo != Glib::ustring(""))
		{
			int n = 0;
			Gtk::TreeModel::iterator iter = selezione_capo_liststore->children().begin();
			Gtk::TreeModel::iterator end = selezione_capo_liststore->children().end();
			while ( iter != end )
			{
				Gtk::TreeModel::Row row = *iter;
				if ( row[button_popup_listmodel->column] == capo )
				{
					selezione_capo_combobox->set_active ( n );
					result = true;
					break;
				}
				n++;
				iter++;
			}
		}
		else
			result = true;
		load_prestazione_popup_button ();
		reconnect_capo_popup ();
		return result;
	}
	return result;
}

/**
 * aggiorna la selezione del tasto popup delle prestazioni con la descrizione passata come parametro
 * */
void Controller::
update_prestazioni_popup_button ( const Glib::ustring descrizione )
{
	Glib::ustring desc_button;
	if ( selezione_prestazione_combobox->get_active_row_number () > -1 )
	{
		Gtk::TreeModel::iterator it_popup = selezione_prestazione_combobox->get_active ();
		Gtk::TreeModel::Row row_popup = *it_popup;
		desc_button = row_popup[button_popup_listmodel->column];
	}
	if ( descrizione != desc_button )
		{
			disconnect_prestazione_popup ();
			selezione_prestazione_combobox->set_active ( -1 );
			if ( descrizione != Glib::ustring(""))
			{
				int n = 0;
				Gtk::TreeModel::iterator iter = selezione_prestazione_liststore->children().begin();
				Gtk::TreeModel::iterator end = selezione_prestazione_liststore->children().end();
				while ( iter != end )
				{
					Gtk::TreeModel::Row row = *iter;
					if ( row[button_popup_listmodel->column] == descrizione )
					{
						selezione_prestazione_combobox->set_active ( n );
						break;
					}
					n++;
					iter++;
				}
			}
			reconnect_prestazione_popup ();
		}
}

/**
 * funzione chiamata quando la riga viene espansa
 * seleziona la riga soggetta ad espansione
 * */
void Controller::
on_prestazioni_ricevuta_row_expanded (const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path)
{
	disconnect_prestazioni_ricevuta ();
	Gtk::TreeModel::Row row = *iter;
	prestazioni_ricevuta_treeselection->select(row);
	reconnect_prestazioni_ricevuta ();
}

/**
 * funzione chiamata quando si cambia la selezione del tasto popup delle prestazioni
 * */
void Controller::
on_selezione_prestazione_popup_changed ( void )
{
	// verifica che sia selezionata una prestazione
	if ( selezione_prestazione_combobox->get_active_row_number () >= 0 )
	{
		add_prestazione_ricevuta_button->set_sensitive (true);
		Gtk::TreeModel::iterator iter_popup = selezione_prestazione_combobox->get_active();
		Gtk::TreeModel::Row row_popup = *iter_popup;
		Glib::ustring prest_popup_sel = row_popup[button_popup_listmodel->column];
		iter_popup = selezione_capo_combobox->get_active();
		row_popup = *iter_popup;
		Glib::ustring capo_popup_sel = row_popup[button_popup_listmodel->column];
		Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
		
		// verifica se ci sono capi o prestazioni selezionate nel TreeView
		if ( prestazioni_ricevuta_treeselection->count_selected_rows () > 0 )
		{
			Gtk::TreeModel::Path path = get_prestazione_ricevuta_selezionata ();
			Gtk::TreeModel::iterator iter = prestazioni_ricevuta_model->get_iter (path);
			Gtk::TreeModel::Row row = *iter;
			Glib::ustring descrizione = row[prestazioni_ricevuta_treemodel->descrizione];

			// se la descrizione è una stringa vuota allora è stato selezionato un capo
			if (descrizione != Glib::ustring(""))
			{
				path.up();
				iter = prestazioni_ricevuta_model->get_iter (path);
				row = *iter;
			}
			
			// verifica che il capo selezionato sulla lista e quello del tasto popup corrispondono
			if (capo_popup_sel == row[prestazioni_ricevuta_treemodel->capo])
			{
				// itera tra le prestazioni associate al capo per vedere se quella selezionata sul tasto popup è già esistente
				Gtk::TreeModel::Children children = row.children();
				Gtk::TreeModel::Children::iterator iter_child = children.begin();
				Gtk::TreeModel::Children::iterator iter_end = children.end();
				bool found = false;
				while (iter_child != iter_end)
				{
					Gtk::TreeModel::Row row_child = *iter_child;
					if (prest_popup_sel == Glib::ustring(row_child[prestazioni_ricevuta_treemodel->descrizione]))
					{
						found = true;
						break;
					}
					iter_child++;
				}
				if (!found)
				{
					// aggiunge la prestazione selezionata al capo
					float prezzo = 0.0;
					set<Prestazione>::iterator iter_prst = find_prestazione (Glib::ustring(row[prestazioni_ricevuta_treemodel->capo]), prest_popup_sel);
					if (iter_prst != prestazioni->end())
						prezzo = iter_prst->get_prezzo();
					Gtk::TreeModel::iterator new_child_iter = prestazioni_ricevuta_treestore->append(children);
					Gtk::TreeModel::Row new_child_row = *new_child_iter;
					new_child_row[prestazioni_ricevuta_treemodel->descrizione] = prest_popup_sel;
					new_child_row[prestazioni_ricevuta_treemodel->prezzo] = Prestazione::get_valuta_string(prezzo);
					update_totale_nuova_ricevuta(prezzo);
					return;
				}
			}
		}
		// aggiunge un nuovo capo con la prestazione selezionata
		Gtk::TreeModel::Children main_children = prestazioni_ricevuta_model->children();
		Gtk::TreeModel::Children::iterator iter_main = main_children.begin();

		// conta il numero dei capi per determinare il numero del nuovo capo
		unsigned int n = 0;
		while (iter_main != main_children.end())
		{
			n++;
			iter_main++;
		}
		
		Gtk::TreeModel::iterator iterTree = prestazioni_ricevuta_treestore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_ricevuta_treemodel->numero] = Glib::ustring::format(setfill(L'0'), setw(2), n + 1);
		row[prestazioni_ricevuta_treemodel->capo] = capo_popup_sel;
		Gtk::TreeModel::iterator iterRowChild = prestazioni_ricevuta_treestore->append(row.children());
		Gtk::TreeModel::Row childRow = *iterRowChild;
		childRow[prestazioni_ricevuta_treemodel->descrizione] = prest_popup_sel;
		float prezzo = 0.0;
		set<Prestazione>::iterator iter_prst = find_prestazione (capo_popup_sel, prest_popup_sel);
		if (iter_prst != prestazioni->end())
			prezzo = iter_prst->get_prezzo();
		childRow[prestazioni_ricevuta_treemodel->prezzo] = Prestazione::get_valuta_string(prezzo);
		update_totale_nuova_ricevuta(prezzo);

		// seleziona il nuovo capo creato
		prestazioni_ricevuta_treeselection->select(iterTree);
	}
	else
		add_prestazione_ricevuta_button->set_sensitive (false);
}

/**
 * funzione chiamata quando si cliccla sul tasto di addizione delle prestazioni
 * */
void Controller::
on_add_prestazione_ricevuta_action ( void )
{
	if ( selezione_capo_combobox->get_active_row_number () >= 0 && selezione_prestazione_combobox->get_active_row_number () >= 0 )
	{
		Gtk::TreeModel::iterator iter_popup = selezione_prestazione_combobox->get_active();
		Gtk::TreeModel::Row row_popup = *iter_popup;
		Glib::ustring prest_popup_sel = row_popup[button_popup_listmodel->column];
		iter_popup = selezione_capo_combobox->get_active();
		row_popup = *iter_popup;
		Glib::ustring capo_popup_sel = row_popup[button_popup_listmodel->column];
		Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
		Gtk::TreeModel::Children main_children = prestazioni_ricevuta_model->children();
		Gtk::TreeModel::Children::iterator iter_main = main_children.begin();

		// conta il numero dei capi per determinare il numero del nuovo capo
		unsigned int n = 0;
		while (iter_main != main_children.end())
		{
			n++;
			iter_main++;
		}
		
		Gtk::TreeModel::iterator iterTree = prestazioni_ricevuta_treestore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[prestazioni_ricevuta_treemodel->numero] = Glib::ustring::format(setfill(L'0'), setw(2), n + 1);
		row[prestazioni_ricevuta_treemodel->capo] = capo_popup_sel;
		Gtk::TreeModel::iterator iterRowChild = prestazioni_ricevuta_treestore->append(row.children());
		Gtk::TreeModel::Row childRow = *iterRowChild;
		childRow[prestazioni_ricevuta_treemodel->descrizione] = prest_popup_sel;
		float prezzo = 0.0;
		set<Prestazione>::iterator iter_prst = find_prestazione (capo_popup_sel, prest_popup_sel);
		if (iter_prst != prestazioni->end())
			prezzo = iter_prst->get_prezzo();
		childRow[prestazioni_ricevuta_treemodel->prezzo] = Prestazione::get_valuta_string(prezzo);
		update_totale_nuova_ricevuta(prezzo);
	}
}

/**
 * riassegna i numeri ai capi in ordine crescente
 * */
void Controller::
riordina_numeri_capi ( void )
{
	Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
	Gtk::TreeModel::Children main_children = prestazioni_ricevuta_model->children();
	Gtk::TreeModel::Children::iterator iter_main = main_children.begin();
	Gtk::TreeModel::Children::iterator end_main = main_children.end();

	// itera tra i capi e riassegna i numeri
	unsigned int n = 1;
	while (iter_main != end_main)
	{
		Gtk::TreeModel::Row row = *iter_main;
		row[prestazioni_ricevuta_treemodel->numero] = Glib::ustring::format(setfill(L'0'), setw(2), n);
		n++;
		iter_main++;
	}
}

/**
 * funzione chiamata quando si cliccla sul tasto di rimozione delle prestazioni
 * */
void Controller::
on_remove_prestazione_ricevuta_action ( void )
{
	// verifica se ci sono capi o prestazioni selezionate nel TreeView
	if ( prestazioni_ricevuta_treeselection->count_selected_rows () > 0 )
	{
		disconnect_prestazioni_ricevuta ();
		Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
		Gtk::TreeModel::Path path = get_prestazione_ricevuta_selezionata ();
		Gtk::TreeModel::iterator iter = prestazioni_ricevuta_model->get_iter (path);
		Gtk::TreeModel::Row row = *iter;
		Glib::ustring descrizione = row[prestazioni_ricevuta_treemodel->descrizione];

		// se la descrizione è una stringa vuota allora è stato selezionato un capo
		if (descrizione != Glib::ustring(""))
		{
			float prezzo = atof(Glib::ustring(row[prestazioni_ricevuta_treemodel->prezzo]).c_str());
			path.up();
			Gtk::TreeModel::iterator main_iter = prestazioni_ricevuta_model->get_iter (path);
			Gtk::TreeModel::Row main_row = *main_iter;
			Gtk::TreeModel::Children children = main_row.children();
			prestazioni_ricevuta_treestore->erase(iter);
			
			// se non ci sono altre prestazioni allora il capo viene eliminato
			if (children.empty())
				prestazioni_ricevuta_treestore->erase(main_iter);
			
			update_totale_nuova_ricevuta (-prezzo);
		}
		else
		{
			// è stato selezionato un capo
			float totale = 0.0;
			
			// itera tra le prestazioni del capo selezionato per calcolare il valore totale dei prezzi
			Gtk::TreeModel::Children children = row.children();
			Gtk::TreeModel::Children::iterator iter_child = children.begin();
			Gtk::TreeModel::Children::iterator end_child = children.end();
			while (iter_child != end_child)
			{
				Gtk::TreeModel::Row child_row = *iter_child;
				totale += atof(Glib::ustring(child_row[prestazioni_ricevuta_treemodel->prezzo]).c_str());
				iter_child++;
			}
			prestazioni_ricevuta_treestore->erase(iter);
			update_totale_nuova_ricevuta (-totale);
		}
		riordina_numeri_capi();
		selezione_capo_combobox->set_active (-1);
		reconnect_prestazioni_ricevuta ();
		prestazioni_ricevuta_treeselection->unselect_all();
	}
}

void Controller::
on_prezzo_modificato ( const Glib::ustring& path, const Glib::ustring& new_text )
{
	Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model();
	Gtk::TreeModel::iterator iter = prestazioni_ricevuta_model->get_iter( path );
	Gtk::TreeModel::Row row = *iter;
	Glib::ustring descrizione = row[prestazioni_ricevuta_treemodel->descrizione];

	// se la descrizione è una stringa vuota allora è stato selezionato un capo
	if (descrizione == Glib::ustring(""))
	{
		// è stato modificato il prezzo di un capo
		row[prestazioni_ricevuta_treemodel->prezzo] = Glib::ustring("");
	}
	else
	{
		// è stato modificato il prezzo di una prestazione
		float totale = ricalcola_totale_nuova_ricevuta();
		totale_ricevuta_label->set_text ( Prestazione::get_valuta_string( totale ) );
		
		if ( pagato_radiobutton->get_active ())
			acconto_ricevuta_entry->set_text (Prestazione::get_valuta_string(totale));
	}
}

/**
 * aggiorna il totale della ricevuta sommando il valore delta
 * */
void Controller::
update_totale_nuova_ricevuta ( float delta )
{
	Glib::ustring totale_str = totale_ricevuta_label->get_text();
	float totale = atof (totale_str.c_str()) + delta;
	totale_ricevuta_label->set_text (Prestazione::get_valuta_string(totale));
}

/**
 * itera tra i capi e le relative prestazioni sommando tutti i prezzi per calcolare il totale della ricevuta
 * */
float Controller::
ricalcola_totale_nuova_ricevuta ( void )
{
	float totale = 0.0;
	Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
	Gtk::TreeModel::Children main_children = prestazioni_ricevuta_model->children();
	Gtk::TreeModel::Children::iterator iter_main = main_children.begin();
	Gtk::TreeModel::Children::iterator end_main = main_children.end();
	while ( iter_main != end_main )
	{
		Gtk::TreeModel::Row main_row = *iter_main;
		Gtk::TreeModel::Children row_children = main_row.children();
		Gtk::TreeModel::Children::iterator iter_child = row_children.begin();
		Gtk::TreeModel::Children::iterator end_child = row_children.end();
		while (iter_child != end_child)
		{
			Gtk::TreeModel::Row child_row = *iter_child;
			totale += atof(Glib::ustring(child_row[prestazioni_ricevuta_treemodel->prezzo]).c_str());
			iter_child++;
		}
		iter_main++;
	}
	return totale;
}

void Controller::
on_pagamento_anticipato_toggled ( void )
{
	if ( pagato_radiobutton->get_active () )
	{
		acconto_ricevuta_entry->set_text (Prestazione::get_valuta_string(atof (totale_ricevuta_label->get_text().c_str())));
		acconto_ricevuta_entry->set_sensitive ( false );
	}
	else
	{
		acconto_ricevuta_entry->set_text ("0,0");
		acconto_ricevuta_entry->set_sensitive ( true );
		acconto_ricevuta_entry->grab_focus();
	}
}

void Controller::
on_conferma_ricevuta_button_action ( void )
{
	Ricevuta rcvt;
	int nrSel = ricevute_treeselection->count_selected_rows ();
	Glib::ustring cliente = cliente_ricevuta_entry->get_text ();
	bool urgente = urgente_ricevuta_checkbutton->get_active ();
	float totale = atof ( totale_ricevuta_label->get_text ().c_str() );
	time_t data_accettazione = parse_data_string ( data_accettazione_ricevuta_entry->get_text() );
	time_t data_ritiro = parse_data_string ( data_ritiro_ricevuta_entry->get_text() );
	if ( cliente != Glib::ustring ( "" ) )
	{
		if ( totale > 0.0 )
		{
			if ( data_ritiro > data_accettazione )
			{
				if ( nrSel == 0 )   // nuova ricevuta
				{
					rcvt.set_nome_cliente ( cliente );
					rcvt.set_numero ( Ricevuta::generate_next_numero_ricevuta() );
					rcvt.set_urgente ( urgente );
					rcvt.set_data_accettazione ( data_accettazione );
					rcvt.set_data_ritiro ( data_ritiro );
					rcvt.set_acconto ( atof( acconto_ricevuta_entry->get_text().c_str() ) );
					Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
					Gtk::TreeModel::Children main_children = prestazioni_ricevuta_model->children();
					Gtk::TreeModel::Children::iterator iter_main = main_children.begin();
					Gtk::TreeModel::Children::iterator end_main = main_children.end();
					while ( iter_main != end_main )
					{
						Gtk::TreeModel::Row main_row = *iter_main;
						Glib::ustring capo = main_row[prestazioni_ricevuta_treemodel->capo];
						unsigned int numero = atoi(Glib::ustring(main_row[prestazioni_ricevuta_treemodel->numero]).c_str());
						Capo cp = Capo (capo, numero);
						Gtk::TreeModel::Children row_children = main_row.children();
						Gtk::TreeModel::Children::iterator iter_child = row_children.begin();
						Gtk::TreeModel::Children::iterator end_child = row_children.end();
						while (iter_child != end_child)
						{
							Gtk::TreeModel::Row child_row = *iter_child;
							Glib::ustring prezzo = child_row[prestazioni_ricevuta_treemodel->prezzo];
							Prestazione temp ( capo, Glib::ustring(child_row[prestazioni_ricevuta_treemodel->descrizione]), atof( prezzo.c_str() ) );
							if (!cp.aggiungi_prestazione(temp))
								cerr << "ERRORE! on_conferma_ricevuta_button_action():: non ho aggiunto la prestazione al capo!" << endl;
							iter_child++;
						}
						rcvt.aggiungi_capo(cp);
						iter_main++;
					}
					if ( rcvt.get_acconto () > rcvt.get_totale() )
						rcvt.set_acconto (rcvt.get_totale());
					ricevute->insert(rcvt);
					on_items_treeselection_changed ();
				}
				else
				{   // modifica ricevuta
					vector<Gtk::TreePath> selected = ricevute_treeselection->get_selected_rows ();
					Glib::RefPtr<Gtk::TreeModel> ricevute_treemodel = ricevute_treeview->get_model ();
					vector<Gtk::TreePath>::const_iterator iter = selected.begin ();
					vector<Gtk::TreePath>::const_iterator end = selected.end ();
					set<Ricevuta>::iterator iter_ricevute;
					set<Ricevuta>::iterator end_ricevute = ricevute->end();
					while ( iter != end )
					{
						Gtk::TreeModel::iterator iter_view = ricevute_treemodel->get_iter ( *iter );
						iter_ricevute = get_ricevuta_iterator ( *iter_view );
						if ( iter_ricevute != end_ricevute )
						{
							if ( nrSel == 1 )
							{
								rcvt = *iter_ricevute;
								rcvt.set_nome_cliente ( cliente );
								rcvt.set_urgente ( urgente );
								rcvt.set_data_accettazione ( data_accettazione );
								rcvt.set_data_ritiro ( data_ritiro );
								rcvt.set_acconto ( atof( acconto_ricevuta_entry->get_text().c_str() ) );
								rcvt.clear_capi ();
								Glib::RefPtr<Gtk::TreeModel> prestazioni_ricevuta_model = prestazioni_ricevuta_treeview->get_model ();
								Gtk::TreeModel::Children main_children = prestazioni_ricevuta_model->children();
								Gtk::TreeModel::Children::iterator iter_main = main_children.begin();
								Gtk::TreeModel::Children::iterator end_main = main_children.end();
								while ( iter_main != end_main )
								{
									Gtk::TreeModel::Row main_row = *iter_main;
									Glib::ustring capo = main_row[prestazioni_ricevuta_treemodel->capo];
									unsigned int numero = atoi(Glib::ustring(main_row[prestazioni_ricevuta_treemodel->numero]).c_str());
									Capo cp = Capo (capo, numero);
									Gtk::TreeModel::Children row_children = main_row.children();
									Gtk::TreeModel::Children::iterator iter_child = row_children.begin();
									Gtk::TreeModel::Children::iterator end_child = row_children.end();
									while (iter_child != end_child)
									{
										Gtk::TreeModel::Row child_row = *iter_child;
										Glib::ustring prezzo = child_row[prestazioni_ricevuta_treemodel->prezzo];
										Prestazione temp ( capo, Glib::ustring(child_row[prestazioni_ricevuta_treemodel->descrizione]), atof( prezzo.c_str() ) );
										if (!cp.aggiungi_prestazione(temp))
											cerr << "ERRORE! on_conferma_ricevuta_button_action():: non ho aggiunto la prestazione al capo!" << endl;
										iter_child++;
									}
									rcvt.aggiungi_capo(cp);
									iter_main++;
								}
								replace_items (ricevute,  iter_ricevute, rcvt);
							}
						}
						else
							cerr << "ERRORE! on_conferma_ricevuta_button_action():: non ho trovato la ricevuta da modificare!" << endl;
						iter++;
					}
				}
				Cliente clnt;
				ricevute_changed = true;
				salva_menuitem->set_sensitive(true);
				load_ricevute_in_treeview ();
				new_ricevuta_window->hide();
				clnt.set_nome ( cliente );
				set<Cliente>::iterator found = clienti->find(clnt);
				if ( found == clienti->end() )
				{
					Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, "Questo cliente non è presente nel database, vuoi registrarlo ora?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
					int res_id = alert_dialog->run();
					delete alert_dialog;
					if ( res_id == Gtk::RESPONSE_YES )
					{
						on_new_cliente_action ();
						nome_cliente_entry->set_text ( cliente );
					}
				}
				if ( stampa_ricevuta_checkbutton->get_active () )
				{
					print_or_preview_ricevuta(Gtk::PRINT_OPERATION_ACTION_PRINT, rcvt.get_ricevuta_string (preferenze.get_stampa_numero_ricevuta()));

					const list<Capo>* capi = rcvt.get_capi();
					list<Capo>::const_iterator iter_cp = capi->begin();
					list<Capo>::const_iterator end_cp = capi->end();
					while ( iter_cp != end_cp)
					{
						print_or_preview_etichetta (Gtk::PRINT_OPERATION_ACTION_PRINT, rcvt.get_etichetta_string (iter_cp, preferenze.get_stampa_numero_ricevuta()));
						iter_cp++;
					}
					
					print_or_preview_ricevuta(Gtk::PRINT_OPERATION_ACTION_PRINT, rcvt.get_ricevuta_string (preferenze.get_stampa_numero_ricevuta()));
				}
			}
			else
			{
				Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_ricevuta_window, "La <b>data di ritiro</b> non può essere antecedente a quella di <b>accettazione</b>.", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
				int res_id = alert_dialog->run();
				delete alert_dialog;
			}
		}
		else
		{
			Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_ricevuta_window, "Il <b>totale</b> è uguale a zero, aggiungere almeno una prestazione.", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
			int res_id = alert_dialog->run();
			delete alert_dialog;
		}
	}
	else
	{
		Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_ricevuta_window, "Non è stato inserito il <b>nome del cliente</b>.", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
		int res_id = alert_dialog->run();
		delete alert_dialog;
	}
}

void Controller::
load_capi_in_prestazione_completion ( void )
{
	capo_liststore->clear();
	map<Glib::ustring,int>::iterator iter = mappa_capi->begin();
	map<Glib::ustring,int>::iterator iterEnd = mappa_capi->end();
	while (iter != iterEnd)
	{
		Gtk::TreeModel::iterator iterTree = capo_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[button_popup_listmodel->column] = iter->first;
		iter++;
	}
}

void Controller::
on_new_prestazione_confirm_button_clicked ( void )
{
	Glib::ustring capo = capo_prestazione_entry->get_text ();
	Glib::ustring descrizione = descrizione_prestazione_entry->get_text ();
	Glib::ustring prezzo = prezzo_prestazione_entry->get_text ();
	int nrSel = prestazioni_treeselection->count_selected_rows ();
	if ( capo != Glib::ustring ( "" ) )
	{
		if ( descrizione != Glib::ustring ( "" ) )
		{
			if ( nrSel == 0 )
			{	
				Prestazione prst ( capo, descrizione, prezzo );
				set<Prestazione>::iterator found = prestazioni->find(prst);
				if ( found != prestazioni->end() )
				{
					Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_prestazione_window, "La stessa prestazione è già presente nel preziario, vuoi sostituirla con questa?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
					int res_id = alert_dialog->run();
					delete alert_dialog;
					if ( res_id == Gtk::RESPONSE_YES )
						replace_items (prestazioni, found, prst);
				}
				else
				{
					prestazioni->insert(prst);
					on_items_treeselection_changed ();
					if(mappa_capi->count(prst.get_capo ()))
						mappa_capi->at(prst.get_capo ()) += 1;
					else
					{
						mappa_capi->insert ( pair<Glib::ustring,int>(prst.get_capo (),1) );
						load_capo_popup_button ();
						load_capi_in_prestazione_completion ();
					}
				}
			}
			else
			{
				vector<Gtk::TreePath> selected = prestazioni_treeselection->get_selected_rows ();
				Glib::RefPtr<Gtk::TreeModel> prestazioni_treemodel = prestazioni_treeview->get_model ();
				vector<Gtk::TreePath>::const_iterator iter = selected.begin ();
				vector<Gtk::TreePath>::const_iterator end = selected.end ();
				set<Prestazione>::iterator iter_prestazioni;
				set<Prestazione>::iterator end_prestazioni = prestazioni->end();
				while ( iter != end )
				{
					Gtk::TreeModel::iterator iter_view = prestazioni_treemodel->get_iter ( *iter );
					iter_prestazioni = get_prestazione_iterator ( *iter_view );
					if ( iter_prestazioni != end_prestazioni )
					{
						if ( nrSel == 1 )
						{
							Prestazione prst (capo, descrizione, prezzo);
							if(mappa_capi->count(capo))
								mappa_capi->at(capo) += 1;
							else
							{
								mappa_capi->insert ( pair<Glib::ustring,int>(capo,1) );
								load_capo_popup_button ();
								load_capi_in_prestazione_completion ();
							}
							replace_items (prestazioni, iter_prestazioni, prst);
						}
					}
					else
						cerr << "ERRORE! on_new_prestazione_confirm_button_clicked():: non ho trovato la prestazione da modificare!" << endl;
					iter++;
				}
			}
			prestazioni_changed = true;
			salva_menuitem->set_sensitive(true);
			load_prestazioni_in_treeview ();
			new_prestazione_window->hide();
		}
		else
		{
			Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_prestazione_window, "La <b>descrizione</b> della prestazione non può essere vuota!", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
			int res_id = alert_dialog->run();
			delete alert_dialog;
		}
	}
	else
	{
		Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_prestazione_window, "Il <b>capo</b> della prestazione non può essere vuoto!", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
		int res_id = alert_dialog->run();
		delete alert_dialog;
	}
}

void Controller::
on_new_cliente_confirm_button_clicked ( void )
{
	bool result = true;
	Glib::ustring nome = nome_cliente_entry->get_text ();
	Glib::ustring telefono = telefono_cliente_entry->get_text ();
	int nrSel = clienti_treeselection->count_selected_rows ();
	if ( nome != Glib::ustring ( "" ) )
	{
		if ( nrSel == 0 )
		{
			Cliente clnt;
			clnt.set_nome ( nome );
			clnt.set_telefono ( telefono );
			set<Cliente>::iterator found = clienti->find(clnt);
			if ( found != clienti->end() )
			{
				Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_cliente_window, "Lo stesso cliente è già presente, vuoi aggiornarlo con questi dati?", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
				int res_id = alert_dialog->run();
				delete alert_dialog;
				if ( res_id == Gtk::RESPONSE_YES )
					replace_items (clienti, found, clnt);
			}
			else
			{
				clienti->insert(clnt);
				on_items_treeselection_changed ();
			}
		}
		else
		{
			vector<Gtk::TreePath> selected = clienti_treeselection->get_selected_rows ();
			Glib::RefPtr<Gtk::TreeModel> clienti_treemodel = clienti_treeview->get_model ();
			vector<Gtk::TreePath>::const_iterator iter = selected.begin ();
			vector<Gtk::TreePath>::const_iterator end = selected.end ();
			set<Cliente>::iterator iter_clienti;
			set<Cliente>::iterator end_clienti = clienti->end();
			while ( iter != end )
			{
				Gtk::TreeModel::iterator iter_view = clienti_treemodel->get_iter ( *iter );
				iter_clienti = get_cliente_iterator ( *iter_view );
				if ( iter_clienti != end_clienti )
				{
					Cliente clnt;
					if ( nrSel == 1 )
					{
						clnt.set_nome(nome);
						clnt.set_telefono(telefono);
						if (clnt.get_nome().raw() == iter_clienti->get_nome().raw() && clnt.get_telefono().raw() == iter_clienti->get_telefono().raw())
							result = false;
						else
							replace_items (clienti, iter_clienti, clnt);
					}
				}
				else
					cerr << "ERRORE! on_new_cliente_confirm_button_clicked():: non ho trovato il cliente da modificare!" << endl;
				iter++;
			}
		}
		if (result)
		{
			clienti_changed = true;
			salva_menuitem->set_sensitive(true);
			load_clienti_in_treeview ();
			new_cliente_window->hide();
		}
	}
	else
	{
		Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *new_cliente_window, "Il <b>nome</b> del cliente non può essere vuoto!", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
		int res_id = alert_dialog->run();
		delete alert_dialog;
	}
}

void Controller::
on_calendario_window_hide ( void )
{
	data_modificata_connection.disconnect ();
}

void Controller::
on_data_modificata ( void )
{
	Glib::ustring data_ora_string;
	Gtk::Entry *working_entry;
	if ( calendario_window->get_title () == Glib::ustring( "Accettazione" ) )
		working_entry = data_accettazione_ricevuta_entry;
	if ( calendario_window->get_title () == Glib::ustring( "Ritiro" ) )
		working_entry = data_ritiro_ricevuta_entry;
	data_ora_string = working_entry->get_text();
	time_t tempo = parse_data_string (data_ora_string);
	struct tm *data_ora = localtime( &tempo );
	int hour = data_ora->tm_hour;
	int min = data_ora->tm_min;
	int sec = data_ora->tm_sec;
	Glib::Date data_scelta;
	main_calendar->get_date(data_scelta);
	data_scelta.to_struct_tm (*data_ora);
	if ( working_entry == data_ritiro_ricevuta_entry )
	{
		if ( SABATO )
		{
			data_ora->tm_hour = 12;
			data_ora->tm_min = 0;
			data_ora->tm_sec = 0;
		}
		else
		{
			data_ora->tm_hour = 17;
			data_ora->tm_min = 30;
			data_ora->tm_sec = 0;
		}	
	}
	else
	{
		data_ora->tm_hour = hour;
		data_ora->tm_min = min;
		data_ora->tm_sec = sec;
	}
	tempo = mktime(data_ora);
	working_entry->set_text ( Ricevuta::get_string_data(tempo, HUMAN_FORMAT) );
}

void Controller::
on_visualizza_numero_toggled(void)
{
	preferenze.set_visualizza_numero_ricevuta (visualizza_numero_ricevuta_checkbutton->get_active());
	update_visualizza_numero(preferenze.get_visualizza_numero_ricevuta());
}

void Controller::
update_visualizza_numero(bool visualizza)
{
	numero_ricevuta_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_lunedi_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_martedi_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_mercoledi_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_giovedi_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_venerdi_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_sabato_treeviewcolumn->set_visible(visualizza);
	numero_ricevuta_resoconto_treeviewcolumn->set_visible(visualizza);
}

void Controller::
on_salva_preferenze_action ( void )
{
	preferenze.set_intestazione_ricevuta (intestazione_textbuffer->get_text());
	preferenze.set_saluto_ricevuta (saluto_textbuffer->get_text ());
	preferenze.set_eliminazione_ricevute (eliminazione_ricevute_combobox->get_active_row_number());
	preferenze.set_azzeramento_numero (azzeramento_numero_combobox->get_active_row_number());
	preferenze.set_salvataggio_automatico (salvataggio_uscita_combobox->get_active_row_number());
	preferenze.set_stampa_numero_ricevuta (stampa_numero_ricevuta_checkbutton->get_active());
	preferenze.set_visualizza_numero_ricevuta (visualizza_numero_ricevuta_checkbutton->get_active());
	save_preferences( pref_path );
	preferenze_window->hide();
}

bool Controller::
eliminazione_automatica ( void )
{
	bool result = false;
	if ( preferenze.get_eliminazione_ricevute () > 0 )
	{
		time_t inizio, fine;
		calcola_periodo_tempo ( inizio, fine, preferenze.get_eliminazione_ricevute () - 1 );
		struct tm *data_ora;
		data_ora = localtime (&inizio);
		data_ora = localtime (&fine);
		set<Ricevuta> vecchie;
		set<Ricevuta>::iterator iter = ricevute->begin();
		set<Ricevuta>::iterator end = ricevute->end();
		while ( iter != end )
		{
			if ( iter->is_consegnato () )
			{
				if ( iter->get_data_ritiro () < inizio )
					vecchie.insert(*iter);
			}
			iter++;
		}
		if ( vecchie.size() > 0 )
		{
			iter = vecchie.begin();
			end = vecchie.end();
			while ( iter != end )
			{
				ricevute->erase(*iter);
				iter++;
			}
			load_ricevute_in_treeview ();
			aggiorna_pagina_calendario ();
			result = true;
		}
	}
	return result;
}

void Controller::
load_clienti_in_finestra_suggerimento ( void )
{
	clienti_suggerimento_liststore->clear();
	set<Cliente>::iterator iter = clienti->begin();
	set<Cliente>::iterator iterEnd = clienti->end();
	while (iter != iterEnd)
	{
		Gtk::TreeModel::iterator iterTree = clienti_suggerimento_liststore->append();
		Gtk::TreeModel::Row row = *iterTree;
		row[clienti_listmodel->nome] = iter->get_nome ();
		iter++;
	}
}

void Controller::
on_suggerimento_clienti_double_clicked ( GdkEventButton *event )
{
	if ( event->type == GDK_2BUTTON_PRESS )
	{
		vector<Gtk::TreePath> selected = clienti_suggerimento_treeselection->get_selected_rows ();
		int nr_sel = clienti_suggerimento_treeselection->count_selected_rows ();
		Glib::RefPtr<Gtk::TreeModel> clienti_treemodel = clienti_suggerimento_treeview->get_model ();
		if ( nr_sel > 0 )
		{
			vector<Gtk::TreePath>::const_iterator iter = selected.begin ();
			Gtk::TreeModel::iterator iter_view = clienti_treemodel->get_iter ( *iter );
			Gtk::TreeModel::Row row = *iter_view;
			cliente_ricevuta_entry->set_text ( row[clienti_listmodel->nome] );
		}
		suggerimento_clienti_window->hide();
	}
}

void Controller::
on_signal_preferenze_loaded ( const Preferenze& pref )
{
	preferenze = pref;
}

void Controller::
on_signal_preferenze_loading_end ( void )
{
	// do nothing
}

void Controller::
on_signal_date_file ( time_t tempo )
{
	time_t inizio, fine;
	calcola_periodo_tempo ( inizio, fine, preferenze.get_azzeramento_numero () );
	struct tm *dataora = localtime(&tempo);
	dataora = localtime(&inizio);
	if ( Ricevuta::get_pure_date (tempo) < Ricevuta::get_pure_date (inizio) )
		Ricevuta::set_numero_ricevute_emesse (0);
}

void Controller::
on_signal_cliente_loaded ( const Cliente &clnt )
{
	int res_id = 0;
	set<Cliente>::iterator found = clienti->find(clnt);
	if ( found != clienti->end() )
	{
		if ( starting_app == STATUS_LOADING )
		{
			Cliente duplicato = clnt;
			if ( duplicato.get_telefono () != "" && duplicato.get_telefono () != found->get_telefono () )
			{
				duplicato.set_nome ( clnt.get_nome() + Glib::ustring("/bis") );
				clienti->insert(found, duplicato);
				clienti_caricati++;
			}
		}
		else
		{
			Glib::ustring messaggio = Glib::ustring ( "Il cliente \"" ) + clnt.get_nome () + Glib::ustring ( "\" è già presente, vuoi sostituirlo con quello importato?" );
			Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, messaggio, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
			res_id = alert_dialog->run();
			delete alert_dialog;
			if ( res_id == Gtk::RESPONSE_YES )
			{
				replace_items (clienti, found, clnt);
				clienti_caricati++;
			}
		}
	}
	else
	{
		clienti->insert(clnt);
		clienti_caricati++;
	}
}

void Controller::
on_signal_prestazione_loaded ( const Prestazione &prst )
{
	if(mappa_capi->count(prst.get_capo ()))
		mappa_capi->at(prst.get_capo ()) += 1;
	else
		mappa_capi->insert ( pair<Glib::ustring,int>(prst.get_capo (),1) );
	int res_id = 0;
	set<Prestazione>::iterator found = prestazioni->find(prst);
	if ( found != prestazioni->end() )
	{
		if ( starting_app == STATUS_RUNNING )
		{
			Glib::ustring messaggio = Glib::ustring ( "La prestazione \"" ) + prst.get_descrizione () + Glib::ustring ( "\" è già presente nel preziario, vuoi sostituirla con quella importata?" );
			Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, messaggio, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
			res_id = alert_dialog->run();
			delete alert_dialog;
			if ( res_id == Gtk::RESPONSE_YES )
			{
				replace_items (prestazioni, found, prst);
				prestazioni_caricate++;
			}
		}
	}
	else
	{
		prestazioni->insert(prst);
		prestazioni_caricate++;
	}
}

void Controller::
on_signal_ricevuta_loaded ( const Ricevuta &rcvt )
{
	int res_id = 0;
	set<Ricevuta>::iterator found = ricevute->find(rcvt);
	if ( found != ricevute->end() )
	{
		Glib::ustring messaggio = Glib::ustring ( "La ricevute \"" ) + rcvt.get_nome_cliente () + Glib::ustring ( "\" è già presente nell'archivio, vuoi sostituirla con quella importata?" );
		Gtk::MessageDialog *alert_dialog = new Gtk::MessageDialog ( *main_window, messaggio, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
		res_id = alert_dialog->run();
		delete alert_dialog;
		if ( res_id == Gtk::RESPONSE_YES )
			replace_items (ricevute, found, rcvt);
	}
	else
	{
		ricevute->insert(rcvt);
		ricevute_caricate++;
	}
}

void Controller::
on_signal_importing_clienti_end ( void )
{
	if ( clienti_caricati > 0 )
	{
		load_clienti_in_treeview ();
		load_clienti_in_ricevuta_completion ();
		if ( starting_app == STATUS_RUNNING )
		{
			clienti_changed = true;
			Glib::ustring messaggio = "Importati ";
			messaggio.append ( Glib::ustring::compose ( "%1 clienti", Glib::ustring::format ( clienti_caricati ) ) );
			main_statusbar->pop ( stbrItemDiskId );
			main_statusbar->push ( messaggio, stbrItemDiskId );
		}
	}
}

void Controller::
on_signal_importing_prestazioni_end ( void )
{
	if ( prestazioni_caricate > 0 )
	{
		load_prestazioni_in_treeview ();
		load_capo_popup_button ();
		load_capi_in_prestazione_completion ();
		if ( starting_app == STATUS_RUNNING )
		{
			prestazioni_changed = true;
			Glib::ustring messaggio = "Importate ";
			messaggio.append ( Glib::ustring::compose ( "%1 prestazioni", Glib::ustring::format ( prestazioni_caricate ) ) );
			main_statusbar->pop ( stbrItemDiskId );
			main_statusbar->push ( messaggio, stbrItemDiskId );
		}
	}
}

void Controller::
on_signal_importing_ricevute_end ( void )
{
	Glib::ustring messaggio;
	if ( ricevute_caricate > 0 )
	{
		load_ricevute_in_treeview ();
		if ( starting_app == STATUS_RUNNING )
		{
			ricevute_changed = true;
			messaggio.assign ( Glib::ustring::compose ( "Importate %1 ricevute", Glib::ustring::format ( ricevute_caricate ) ) );
			main_statusbar->pop ( stbrItemDiskId );
			main_statusbar->push ( messaggio, stbrItemDiskId );
		}
	}
	
	if ( starting_app == STATUS_RUNNING )
	{
		if ( clienti_caricati + prestazioni_caricate + ricevute_caricate > 0 )
			salva_menuitem->set_sensitive (true);
	}
	else
	{
		if ( ricevute->size() > 0 && eliminazione_automatica () )
			ricevute_changed = true;
		starting_app = STATUS_RUNNING;
		messaggio.assign ( Glib::ustring::compose ( "Caricati %1 clienti, %2 prestazioni e %3 ricevute", Glib::ustring::format ( clienti_caricati ), Glib::ustring::format ( prestazioni_caricate ), Glib::ustring::format ( ricevute_caricate ) ) );
		main_statusbar->pop ( stbrItemDiskId );
		main_statusbar->push ( messaggio, stbrItemDiskId );
	}
	aggiorna_pagina_calendario ();
}

Glib::ustring Controller::
get_stampa_prestazioni ( set<Ricevuta>::const_iterator iter, size_t line )
{
	Glib::ustring str = "- - - - - - - - - - - - - - - - \n";
	const list<Capo>* capi_ricevuta = iter->get_const_capi ();
	list<Capo>::const_iterator iter_c = capi_ricevuta->begin();
	list<Capo>::const_iterator end_c = capi_ricevuta->end();
	while (iter_c != end_c)
	{
		const list<Prestazione>* prestazioni_capo = iter_c->get_const_prestazioni ();
		list<Prestazione>::const_iterator iter_p = prestazioni_capo->begin();
		list<Prestazione>::const_iterator end_p = prestazioni_capo->end();
		while ( iter_p != end_p )
		{
			Glib::ustring capo = iter_p->get_capo ();
			if ( capo.size() > 6 )
				capo.assign(capo.substr(0,6) + ".");
			Glib::ustring descr = iter_p->get_descrizione ();
			if ( descr.size() > 14 )
				descr.assign(descr.substr(0,14) + ".");
			Glib::ustring str_end = " € " + Prestazione::get_valuta_string(iter_p->get_prezzo());
			Glib::ustring str_start = "1 " + capo + " " + descr;
			str += Ricevuta::get_formatted_line (str_start, str_end, line);
			iter_p++;
		}
		iter_c++;
	}
	return str;
}

void Controller::
on_printoperation_status_changed(const Glib::RefPtr<Gtk::PrintOperation>& operation)
{
	Glib::ustring status_msg;

	if (operation->is_finished())
	{
		status_msg = "Lavoro di stampa inviato alla stampante.";
	}
	else
	{
		status_msg = operation->get_status_string();
	}

	main_statusbar->push(status_msg, stbrPrintId);
}

void Controller::
on_printoperation_done(Gtk::PrintOperationResult result, const Glib::RefPtr<Gtk::PrintOperation>& operation)
{
	//Printing is "done" when the print data is spooled.

	if (result == Gtk::PRINT_OPERATION_RESULT_ERROR)
	{
		Gtk::MessageDialog err_dialog(*main_window, "Error printing form", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
		err_dialog.run();
	}
	else if (result == Gtk::PRINT_OPERATION_RESULT_APPLY)
	{
		//Update PrintSettings with the ones used in this PrintOperation:
		m_refSettings = operation->get_print_settings();
	}

	if (! operation->is_finished())
	{
		//We will connect to the status-changed signal to track status
		//and update a status bar. In addition, you can, for example,
		//keep a list of active print operations, or provide a progress dialog.
		operation->signal_status_changed().connect(sigc::bind(sigc::mem_fun(*this,&Controller::on_printoperation_status_changed),operation));
	}
}

void Controller::
print_or_preview_ricevuta(Gtk::PrintOperationAction print_action, const Glib::ustring &str1)
{
	Glib::RefPtr<RicevutaPrintFormOperation> print = RicevutaPrintFormOperation::create();
	print->set_intestazione (preferenze.get_xml_friendly_intestazione_ricevuta());
	print->set_content (str1);
	print->set_saluto (preferenze.get_xml_friendly_saluto_ricevuta());

	print->set_track_print_status();
	print->set_default_page_setup(m_refPageSetup);
	print->set_print_settings(m_refSettings);

	print->signal_done().connect(sigc::bind ( sigc::mem_fun(*this,&Controller::on_printoperation_done), print ) );
	try
	{
		print->run(print_action, *main_window);
	}
	catch (const Gtk::PrintError& ex)
	{
		cerr << "An error occurred while trying to run a print operation:" << ex.what() << std::endl;
	}
}

void Controller::
print_or_preview_etichetta(Gtk::PrintOperationAction print_action, const Glib::ustring &str1)
{
	Glib::RefPtr<EtichettaPrintFormOperation> print = EtichettaPrintFormOperation::create();
	print->set_content (str1);

	print->set_track_print_status();
	print->set_default_page_setup(m_refPageSetup);
	print->set_print_settings(m_refSettings);

	print->signal_done().connect(sigc::bind ( sigc::mem_fun(*this,&Controller::on_printoperation_done), print ) );
	try
	{
		print->run(print_action, *main_window);
	}
	catch (const Gtk::PrintError& ex)
	{
		cerr << "An error occurred while trying to run a print operation:" << ex.what() << std::endl;
	}
}

void Controller::
print_or_preview_chiusura(Gtk::PrintOperationAction print_action, const Glib::ustring &str1)
{
	Glib::RefPtr<ChiusuraCassaPrintFormOperation> print = ChiusuraCassaPrintFormOperation::create();
	print->set_intestazione (preferenze.get_xml_friendly_intestazione_ricevuta ());
	print->set_content (str1);

	print->set_track_print_status();
	print->set_default_page_setup(m_refPageSetup);
	print->set_print_settings(m_refSettings);

	print->signal_done().connect(sigc::bind ( sigc::mem_fun(*this,&Controller::on_printoperation_done), print ) );
	try
	{
		print->run(print_action, *main_window);
	}
	catch (const Gtk::PrintError& ex)
	{
		cerr << "An error occurred while trying to run a print operation:" << ex.what() << std::endl;
	}
}
